openocd新增flash driver

34 min

文件修改

src/flash/nor/Makefile.am  // %D%/rk3568.c
src/flash/nor/driver.h     // extern const struct flash_driver rk3568_flash;
src/flash/nor/driver.c     // &rk3568_flash,
src/flash/nor/rk3568.c     //新增驱动文件

驱动文件实现内容

主要需要实现如下结构体:

/**
 * @brief Provides the implementation-independent structure that defines
 * all of the callbacks required by OpenOCD flash drivers.
 *
 * Driver authors must implement the routines defined here, providing an
 * instance with the fields filled out.  After that, the instance must
 * be registered in flash.c, so it can be used by the driver lookup system.
 *
 * Specifically, the user can issue the command: @par
 * @code
 * flash bank DRIVERNAME ...parameters...
 * @endcode
 *
 * OpenOCD will search for the driver with a @c flash_driver_s::name
 * that matches @c DRIVERNAME.
 *
 * The flash subsystem calls some of the other drivers routines a using
 * corresponding static <code>flash_driver_<i>callback</i>()</code>
 * routine in flash.c.
 */
struct flash_driver {
	/**
	 * Gives a human-readable name of this flash driver,
	 * This field is used to select and initialize the driver.
	 */
	const char *name;

	/**
	 * Gives a human-readable description of arguments.
	 */
	const char *usage;

	/**
	 * An array of driver-specific commands to register.  When called
	 * during the "flash bank" command, the driver can register addition
	 * commands to support new flash chip functions.
	 */
	const struct command_registration *commands;

	/**
	 * Finish the "flash bank" command for @a bank.  The
	 * @a bank parameter will have been filled in by the core flash
	 * layer when this routine is called, and the driver can store
	 * additional information in its struct flash_bank::driver_priv field.
	 *
	 * The CMD_ARGV are: @par
	 * @code
	 * CMD_ARGV[0] = bank
	 * CMD_ARGV[1] = drivername {name above}
	 * CMD_ARGV[2] = baseaddress
	 * CMD_ARGV[3] = lengthbytes
	 * CMD_ARGV[4] = chip_width_in bytes
	 * CMD_ARGV[5] = bus_width_in_bytes
	 * CMD_ARGV[6] = driver-specific parameters
	 * @endcode
	 *
	 * For example, CMD_ARGV[4] = 2 (for 16 bit flash),
	 *	CMD_ARGV[5] = 4 (for 32 bit bus).
	 *
	 * If extra arguments are provided (@a CMD_ARGC > 6), they will
	 * start in @a CMD_ARGV[6].  These can be used to implement
	 * driver-specific extensions.
	 *
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	__FLASH_BANK_COMMAND((*flash_bank_command));

	/**
	 * Bank/sector erase routine (target-specific).  When
	 * called, the flash driver should erase the specified sectors
	 * using whatever means are at its disposal.
	 *
	 * @param bank The bank of flash to be erased.
	 * @param first The number of the first sector to erase, typically 0.
	 * @param last The number of the last sector to erase, typically N-1.
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	int (*erase)(struct flash_bank *bank, unsigned int first,
		unsigned int last);

	/**
	 * Bank/sector protection routine (target-specific).
	 *
	 * If protection is not implemented, set method to NULL
	 *
	 * When called, the driver should enable/disable protection
	 * for MINIMUM the range covered by first..last sectors
	 * inclusive. Some chips have alignment requirements will
	 * cause the actual range to be protected / unprotected to
	 * be larger than the first..last range.
	 *
	 * @param bank The bank to protect or unprotect.
	 * @param set If non-zero, enable protection; if 0, disable it.
	 * @param first The first sector to (un)protect, typically 0.
	 * @param last The last sector to (un)project, typically N-1.
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	int (*protect)(struct flash_bank *bank, int set, unsigned int first,
		unsigned int last);

	/**
	 * Program data into the flash.  Note CPU address will be
	 * "bank->base + offset", while the physical address is
	 * dependent upon current target MMU mappings.
	 *
	 * @param bank The bank to program
	 * @param buffer The data bytes to write.
	 * @param offset The offset into the chip to program.
	 * @param count The number of bytes to write.
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	int (*write)(struct flash_bank *bank,
			const uint8_t *buffer, uint32_t offset, uint32_t count);

	/**
	 * Read data from the flash. Note CPU address will be
	 * "bank->base + offset", while the physical address is
	 * dependent upon current target MMU mappings.
	 *
	 * @param bank The bank to read.
	 * @param buffer The data bytes read.
	 * @param offset The offset into the chip to read.
	 * @param count The number of bytes to read.
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	 int (*read)(struct flash_bank *bank,
			uint8_t *buffer, uint32_t offset, uint32_t count);

	/**
	 * Verify data in flash.  Note CPU address will be
	 * "bank->base + offset", while the physical address is
	 * dependent upon current target MMU mappings.
	 *
	 * @param bank The bank to verify
	 * @param buffer The data bytes to verify against.
	 * @param offset The offset into the chip to verify.
	 * @param count The number of bytes to verify.
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	int (*verify)(struct flash_bank *bank,
			const uint8_t *buffer, uint32_t offset, uint32_t count);

	/**
	 * Probe to determine what kind of flash is present.
	 * This is invoked by the "probe" script command.
	 *
	 * @param bank The bank to probe
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	int (*probe)(struct flash_bank *bank);

	/**
	 * Check the erasure status of a flash bank.
	 * When called, the driver routine must perform the required
	 * checks and then set the @c flash_sector_s::is_erased field
	 * for each of the flash banks's sectors.
	 *
	 * @param bank The bank to check
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	int (*erase_check)(struct flash_bank *bank);

	/**
	 * Determine if the specific bank is "protected" or not.
	 * When called, the driver routine must must perform the
	 * required protection check(s) and then set the @c
	 * flash_sector_s::is_protected field for each of the flash
	 * bank's sectors.
	 *
	 * If protection is not implemented, set method to NULL
	 *
	 * @param bank - the bank to check
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	int (*protect_check)(struct flash_bank *bank);

	/**
	 * Display human-readable information about the flash
	 * bank.
	 *
	 * @param bank - the bank to get info about
	 * @param cmd - command invocation instance for which to generate
	 *              the textual output
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	int (*info)(struct flash_bank *bank, struct command_invocation *cmd);

	/**
	 * A more gentle flavor of flash_driver_s::probe, performing
	 * setup with less noise.  Generally, driver routines should test
	 * to see if the bank has already been probed; if it has, the
	 * driver probably should not perform its probe a second time.
	 *
	 * This callback is often called from the inside of other
	 * routines (e.g. GDB flash downloads) to autoprobe the flash as
	 * it is programming the flash.
	 *
	 * @param bank - the bank to probe
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	int (*auto_probe)(struct flash_bank *bank);

	/**
	 * Deallocates private driver structures.
	 * Use default_flash_free_driver_priv() to simply free(bank->driver_priv)
	 *
	 * @param bank - the bank being destroyed
	 */
	void (*free_driver_priv)(struct flash_bank *bank);
};

commands

/*
 * Commands should be registered by filling in one or more of these
 * structures and passing them to [un]register_commands().
 *
 * A conventional format should be used for help strings, to provide both
 * usage and basic information:
 * @code
 * "@<options@> ... - some explanation text"
 * @endcode
 *
 * @param name The name of the command to register, which must not have
 * been registered previously in the intended context.
 * @param handler The callback function that will be called.  If NULL,
 * then the command serves as a placeholder for its children or a script.
 * @param mode The command mode(s) in which this command may be run.
 * @param help The help text that will be displayed to the user.
 */
struct command_registration {
	const char *name;
	command_handler_t handler;
	Jim_CmdProc *jim_handler;
	enum command_mode mode;
	const char *help;
	/** a string listing the options and arguments, required or optional */
	const char *usage;

	/**
	 * If non-NULL, the commands in @c chain will be registered in
	 * the same context and scope of this registration record.
	 * This allows modules to inherit lists commands from other
	 * modules.
	 */
	const struct command_registration *chain;
};

实现内容

static const struct command_registration at91sam3_command_handlers[] = {
	{
		.name = "at91sam3",
		.mode = COMMAND_ANY,
		.help = "at91sam3 flash command group",
		.usage = "",
		.chain = at91sam3_exec_command_handlers,
	},
	COMMAND_REGISTRATION_DONE
};
static const struct command_registration stm32l4_command_handlers[] = {
	{
		.name = "stm32l4x",
		.mode = COMMAND_ANY,
		.help = "stm32l4x flash command group",
		.usage = "",
		.chain = stm32l4_exec_command_handlers,
	},
	COMMAND_REGISTRATION_DONE
};

flash_bank_command

/**
	 * Finish the "flash bank" command for @a bank.  The
	 * @a bank parameter will have been filled in by the core flash
	 * layer when this routine is called, and the driver can store
	 * additional information in its struct flash_bank::driver_priv field.
	 *
	 * The CMD_ARGV are: @par
	 * @code
	 * CMD_ARGV[0] = bank
	 * CMD_ARGV[1] = drivername {name above}
	 * CMD_ARGV[2] = baseaddress
	 * CMD_ARGV[3] = lengthbytes
	 * CMD_ARGV[4] = chip_width_in bytes
	 * CMD_ARGV[5] = bus_width_in_bytes
	 * CMD_ARGV[6] = driver-specific parameters
	 * @endcode
	 *
	 * For example, CMD_ARGV[4] = 2 (for 16 bit flash),
	 *	CMD_ARGV[5] = 4 (for 32 bit bus).
	 *
	 * If extra arguments are provided (@a CMD_ARGC > 6), they will
	 * start in @a CMD_ARGV[6].  These can be used to implement
	 * driver-specific extensions.
	 *
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
/**
	 * 完成@a库的“闪存库”命令。 这
	 * @a组参数将由核心闪存填充
	 * 层,并且驱动程序可以存储
	 * 其结构 flash_bank::d river_priv 字段中的其他信息。
	 *
	 * CMD_ARGV是:@par
	 * @code
	 * CMD_ARGV[0] = bank
	 * CMD_ARGV[1] = drivername {上面的名字}
	 * CMD_ARGV[2] = 基址
	 * CMD_ARGV[3] = 长度字节
	 * CMD_ARGV[4] = chip_width_in 字节
	 * CMD_ARGV[5] = bus_width_in_bytes
	 * CMD_ARGV[6] = 特定于驱动程序的参数
	 * @endcode
	 *
	 * 例如,CMD_ARGV[4] = 2(对于 16 位闪存),
	 * CMD_ARGV[5] = 4(对于 32 位总线)。
	 *
	 * 如果提供额外的参数(@a CMD_ARGC > 6),它们将
	 * 从 @a CMD_ARGV[6] 开始。 这些可用于实现
	 * 特定于驱动程序的扩展。
	 *
	 * 如果成功,则@returns ERROR_OK;否则为错误代码。
	 */
	__FLASH_BANK_COMMAND((*flash_bank_command));

传入参数

	#define __FLASH_BANK_COMMAND(name) \

        COMMAND_HELPER(name, struct flash_bank *bank)

/**
 * Provides details of a flash bank, available either on-chip or through
 * a major interface.
 *
 * This structure will be passed as a parameter to the callbacks in the
 * flash_driver_s structure, some of which may modify the contents of
 * this structure of the area of flash that it defines.  Driver writers
 * may use the @c driver_priv member to store additional data on a
 * per-bank basis, if required.
 */
struct flash_bank {
	char *name;

	struct target *target; /**< Target to which this bank belongs. */

	const struct flash_driver *driver; /**< Driver for this bank. */
	void *driver_priv; /**< Private driver storage pointer */

	unsigned int bank_number; /**< The 'bank' (or chip number) of this instance. */
	target_addr_t base; /**< The base address of this bank */
	uint32_t size; /**< The size of this chip bank, in bytes */

	unsigned int chip_width; /**< Width of the chip in bytes (1,2,4 bytes) */
	unsigned int bus_width; /**< Maximum bus width, in bytes (1,2,4 bytes) */

	/** Erased value. Defaults to 0xFF. */
	uint8_t erased_value;

	/** Default padded value used, normally this matches the  flash
	 * erased value. Defaults to 0xFF. */
	uint8_t default_padded_value;

	/** Required alignment of flash write start address.
	 * Default 0, no alignment. Can be any power of two or FLASH_WRITE_ALIGN_SECTOR */
	uint32_t write_start_alignment;
	/** Required alignment of flash write end address.
	 * Default 0, no alignment. Can be any power of two or FLASH_WRITE_ALIGN_SECTOR */
	uint32_t write_end_alignment;
	/** Minimal gap between sections to discontinue flash write
	 * Default FLASH_WRITE_GAP_SECTOR splits the write if one or more untouched
	 * sectors in between.
     * Can be size in bytes or FLASH_WRITE_CONTINUOUS */
	uint32_t minimal_write_gap;

	/**
	 * The number of sectors on this chip.  This value will
	 * be set initially to 0, and the flash driver must set this to
	 * some non-zero value during "probe()" or "auto_probe()".
	 */
	unsigned int num_sectors;
	/** Array of sectors, allocated and initialized by the flash driver */
	struct flash_sector *sectors;

	/**
	 * The number of protection blocks in this bank. This value
	 * is set initially to 0 and sectors are used as protection blocks.
	 * Driver probe can set protection blocks array to work with
	 * protection granularity different than sector size.
	 */
	unsigned int num_prot_blocks;
	/** Array of protection blocks, allocated and initialized by the flash driver */
	struct flash_sector *prot_blocks;

	struct flash_bank *next; /**< The next flash bank on this chip */
};

实现内容

主要包含内部结构内存申请,变量初始化赋值,参数列表处理三部分内容,如下:

FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
{
	struct stm32x_flash_bank *stm32x_info;

	if (CMD_ARGC < 6)
		return ERROR_COMMAND_SYNTAX_ERROR;

	stm32x_info = malloc(sizeof(struct stm32x_flash_bank));

	bank->driver_priv = stm32x_info;
	stm32x_info->probed = false;
	stm32x_info->has_dual_banks = false;
	stm32x_info->can_load_options = false;
	stm32x_info->register_base = FLASH_REG_BASE_B0;
	stm32x_info->user_bank_size = bank->size;

	/* The flash write must be aligned to a halfword boundary */
	bank->write_start_alignment = bank->write_end_alignment = 2;

	return ERROR_OK;
}
FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command)
{
	struct rp2040_flash_bank *priv;
	priv = malloc(sizeof(struct rp2040_flash_bank));
	priv->probed = false;

	/* Set up driver_priv */
	bank->driver_priv = priv;

	return ERROR_OK;
}
/* flash_bank LPC288x 0 0 0 0 <target#> <cclk> */
FLASH_BANK_COMMAND_HANDLER(lpc288x_flash_bank_command)
{
	struct lpc288x_flash_bank *lpc288x_info;

	if (CMD_ARGC < 6)
		return ERROR_COMMAND_SYNTAX_ERROR;

	lpc288x_info = malloc(sizeof(struct lpc288x_flash_bank));
	bank->driver_priv = lpc288x_info;

	/* part wasn't probed for info yet */
	lpc288x_info->cidr = 0;
	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], lpc288x_info->cclk);

	return ERROR_OK;
}
FLASH_BANK_COMMAND_HANDLER(swm050_flash_bank_command)
{
	free(bank->sectors);
	bank->write_start_alignment = 4;
	bank->write_end_alignment = 4;
	bank->size = SWM050_FLASH_PAGE_SIZE * SWM050_FLASH_PAGES;

	bank->num_sectors = SWM050_FLASH_PAGES;
	bank->sectors = alloc_block_array(0, SWM050_FLASH_PAGE_SIZE, SWM050_FLASH_PAGES);
	if (!bank->sectors)
		return ERROR_FAIL;

	for (unsigned int i = 0; i < bank->num_sectors; i++)
		bank->sectors[i].is_protected = 0;

	return ERROR_OK;
}

erase

/**
	 * Bank/sector erase routine (target-specific).  When
	 * called, the flash driver should erase the specified sectors
	 * using whatever means are at its disposal.
	 *
	 * @param bank The bank of flash to be erased.
	 * @param first The number of the first sector to erase, typically 0.
	 * @param last The number of the last sector to erase, typically N-1.
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	 /**
	 * 块/扇区擦除例程(针对特定目标)。  调用时
	 * 闪存驱动程序应使用其所能使用的任何方法擦除指定扇区。
	 *
	 * 参数 bank 要擦除的闪存块。
	 * @param first 要擦除的第一个扇区的编号,通常为 0。
	 * @param last 要擦除的最后一个扇区的编号,通常为 N-1。
	 * 如果成功,则返回 ERROR_OK;否则返回错误代码。
	 */
	int (*erase)(struct flash_bank *bank, unsigned int first,
		unsigned int last);

protect

/**
	 * Bank/sector protection routine (target-specific).
	 *
	 * If protection is not implemented, set method to NULL
	 *
	 * When called, the driver should enable/disable protection
	 * for MINIMUM the range covered by first..last sectors
	 * inclusive. Some chips have alignment requirements will
	 * cause the actual range to be protected / unprotected to
	 * be larger than the first..last range.
	 *
	 * @param bank The bank to protect or unprotect.
	 * @param set If non-zero, enable protection; if 0, disable it.
	 * @param first The first sector to (un)protect, typically 0.
	 * @param last The last sector to (un)project, typically N-1.
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
/**
	 * 块/扇区保护例行程序(针对特定目标)。
	 *
	 * 如果未实施保护,则将方法设为 NULL
	 *
	 * 调用时,驱动程序应启用/禁用保护功能
	 * 最小保护范围为第一个......最后一个扇区
	 * 包含在内。某些芯片的对齐要求会
	 * 导致受保护/不受保护的实际范围
	 * 大于第一个...最后一个扇区的范围。
	 *
	 * @param bank 要保护或取消保护的存储体。
	 * 如果非零,则启用保护;如果为 0,则禁用。
	 * @param first 要(取消)保护的第一个扇区,通常为 0。
	 * @param last 要(解除)保护的最后一个扇区,通常为 N-1。
	 * 如果成功,返回 ERROR_OK;否则,返回错误代码。
	 */
	 
	int (*protect)(struct flash_bank *bank, int set, unsigned int first,
		unsigned int last);

write

/**
	 * Program data into the flash.  Note CPU address will be
	 * "bank->base + offset", while the physical address is
	 * dependent upon current target MMU mappings.
	 *
	 * @param bank The bank to program
	 * @param buffer The data bytes to write.
	 * @param offset The offset into the chip to program.
	 * @param count The number of bytes to write.
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	 /**
	 * 将数据写入闪存。  注意 CPU 地址将是
	 * "bank->base+offset",而物理地址取决于当前目标 MMU 映射。
	 * 取决于当前目标 MMU 映射。
	 *
	 * 参数 bank 要编程的存储体
	 * 要写入的数据字节。
	 * @param offset 要编程的芯片偏移量。
	 * 要写入的字节数。
	 * 如果成功,则返回 ERROR_OK;否则,返回错误代码。
	 */
	int (*write)(struct flash_bank *bank,
			const uint8_t *buffer, uint32_t offset, uint32_t count);

read

/**
	 * Read data from the flash. Note CPU address will be
	 * "bank->base + offset", while the physical address is
	 * dependent upon current target MMU mappings.
	 *
	 * @param bank The bank to read.
	 * @param buffer The data bytes read.
	 * @param offset The offset into the chip to read.
	 * @param count The number of bytes to read.
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	 /**
	 * 从闪存读取数据。注意 CPU 地址将是
	 * "bank->base+offset",而物理地址取决于当前目标 MMU 映射。
	 * 取决于当前目标 MMU 映射。
	 *
	 * @param bank 要读取的存储体。
	 * @param buffer 读取的数据字节。
	 * @param offset 要读取的芯片偏移量。
	 * 要读取的字节数。
	 * 如果成功,则返回 ERROR_OK;否则,返回错误代码。
	 */
	 int (*read)(struct flash_bank *bank,
			uint8_t *buffer, uint32_t offset, uint32_t count);

verify

/**
	 * Verify data in flash.  Note CPU address will be
	 * "bank->base + offset", while the physical address is
	 * dependent upon current target MMU mappings.
	 *
	 * @param bank The bank to verify
	 * @param buffer The data bytes to verify against.
	 * @param offset The offset into the chip to verify.
	 * @param count The number of bytes to verify.
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	 /**
	 * 校验闪存中的数据。  注意 CPU 地址将是
	 * "bank->base+offset",而物理地址取决于当前目标 MMU 映射。
	 * 取决于当前目标 MMU 映射。
	 *
	 * 参数 bank 要验证的 bank
	 * 要验证的数据字节。
	 * @param offset 要验证的芯片偏移量。
	 * @param count 要验证的字节数。
	 * 如果成功,则返回 ERROR_OK;否则,返回错误代码。
	 */
	int (*verify)(struct flash_bank *bank,
			const uint8_t *buffer, uint32_t offset, uint32_t count);

probe

/**
	 * Probe to determine what kind of flash is present.
	 * This is invoked by the "probe" script command.
	 *
	 * @param bank The bank to probe
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	 /**
	 * 探测以确定存在何种闪存。
	 * 由 "probe "脚本命令调用。
	 *
	 * 参数 bank 要探测的存储体
	 * 如果成功,则返回 ERROR_OK;否则,返回错误代码。
	 */
	int (*probe)(struct flash_bank *bank);

erase_check

/**
	 * Check the erasure status of a flash bank.
	 * When called, the driver routine must perform the required
	 * checks and then set the @c flash_sector_s::is_erased field
	 * for each of the flash banks's sectors.
	 *
	 * @param bank The bank to check
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	 /**
	 * 检查闪存组的擦除状态。
	 * 调用时,驱动程序例程必须执行所需的检查,然后设置 @c flash_sector_s::is_erased 字段。
	 * 检查,然后设置每个闪存组扇区的 @c flash_sector_s::is_erased 字段。
	 * 为每个闪存组的扇区设置 @c flash_sector_s::is_erased 字段。
	 *
	 * 要检查的闪存库
	 * 如果成功,则返回 ERROR_OK;否则,返回错误代码。
	 */
	int (*erase_check)(struct flash_bank *bank);

protect_check

/**
	 * Determine if the specific bank is "protected" or not.
	 * When called, the driver routine must must perform the
	 * required protection check(s) and then set the @c
	 * flash_sector_s::is_protected field for each of the flash
	 * bank's sectors.
	 *
	 * If protection is not implemented, set method to NULL
	 *
	 * @param bank - the bank to check
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	 /**
	 * 确定特定银行是否受 "保护"。
	 * 调用时,驱动程序例程必须执行
	 * 必要的保护检查,然后为每个闪存设置 @c
	 * flash_sector_s::is_protected 字段。
	 * 银行扇区。
	 *
	 * 如果未实施保护,则将方法设为 NULL
	 *
	 * @param bank - 要检查的存储体
	 * 如果成功,则返回 ERROR_OK;否则,返回错误代码。
	 */
	int (*protect_check)(struct flash_bank *bank);

info

/**
	 * Display human-readable information about the flash
	 * bank.
	 *
	 * @param bank - the bank to get info about
	 * @param cmd - command invocation instance for which to generate
	 *              the textual output
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	 /**
	 * 显示闪存块的可读信息
	 *
	 * @param bank - 要获取信息的闪存块
	 * @param cmd - 命令调用实例,用于生成
	 * 文本输出
	 * 如果成功,返回 ERROR_OK;否则,返回错误代码。
	 */
	int (*info)(struct flash_bank *bank, struct command_invocation *cmd);

auto_probe

/**
	 * A more gentle flavor of flash_driver_s::probe, performing
	 * setup with less noise.  Generally, driver routines should test
	 * to see if the bank has already been probed; if it has, the
	 * driver probably should not perform its probe a second time.
	 *
	 * This callback is often called from the inside of other
	 * routines (e.g. GDB flash downloads) to autoprobe the flash as
	 * it is programming the flash.
	 *
	 * @param bank - the bank to probe
	 * @returns ERROR_OK if successful; otherwise, an error code.
	 */
	 /**
	 * 更温和的 flash_driver_s::probe,执行
	 * 设置时噪音较小。  一般来说,驱动程序例程应测试
	 * 银行是否已被探测过。
	 * 驱动程序可能不应再次执行探测。
	 *
	 * 该回调通常在其他
	 * 例程(如 GDB 闪存下载)内部调用该回调,以便在对闪存进行编程时自动探测闪存。
	 * 对闪存进行编程。
	 *
	 * 参数 bank - 要探测的存储体
	 * 如果成功,返回 ERROR_OK;否则,返回错误代码。
	 */
	int (*auto_probe)(struct flash_bank *bank);

free_driver_priv

/**
	 * Deallocates private driver structures.
	 * Use default_flash_free_driver_priv() to simply free(bank->driver_priv)
	 *
	 * @param bank - the bank being destroyed
	 */
	 /**
	 * 卸载私有驱动程序结构。
	 * 使用 default_flash_free_driver_priv() 简单地 free(bank->driver_priv)
	 *
	 * @param bank - 被销毁的存储块
	 */
	void (*free_driver_priv)(struct flash_bank *bank);

驱动文件依赖内容

读写内存

int target_read_u64(struct target *target, target_addr_t address, uint64_t *value);
int target_read_u32(struct target *target, target_addr_t address, uint32_t *value);
int target_read_u16(struct target *target, target_addr_t address, uint16_t *value);
int target_read_u8(struct target *target, target_addr_t address, uint8_t *value);
int target_write_u64(struct target *target, target_addr_t address, uint64_t value);
int target_write_u32(struct target *target, target_addr_t address, uint32_t value);
int target_write_u16(struct target *target, target_addr_t address, uint16_t value);
int target_write_u8(struct target *target, target_addr_t address, uint8_t value);

int target_write_phys_u64(struct target *target, target_addr_t address, uint64_t value);
int target_write_phys_u32(struct target *target, target_addr_t address, uint32_t value);
int target_write_phys_u16(struct target *target, target_addr_t address, uint16_t value);
int target_write_phys_u8(struct target *target, target_addr_t address, uint8_t value);

比如sh_qspi的初始化,完全由读写内存构成,原理就是通过读写内存的方式操作spi寄存器。

static int sh_qspi_init(struct flash_bank *bank)
{
	struct target *target = bank->target;
	struct sh_qspi_flash_bank *info = bank->driver_priv;
	uint8_t val;
	int ret;

	/* QSPI initialize */
	/* Set master mode only */
	ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, SPCR_MSTR);
	if (ret != ERROR_OK)
		return ret;

	/* Set SSL signal level */
	ret = target_write_u8(target, info->io_base + SH_QSPI_SSLP, 0x00);
	if (ret != ERROR_OK)
		return ret;

	/* Set MOSI signal value when transfer is in idle state */
	ret = target_write_u8(target, info->io_base + SH_QSPI_SPPCR,
			      SPPCR_IO3FV | SPPCR_IO2FV);
	if (ret != ERROR_OK)
		return ret;

	/* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */
	ret = target_write_u8(target, info->io_base + SH_QSPI_SPBR, 0x01);
	if (ret != ERROR_OK)
		return ret;

	/* Disable Dummy Data Transmission */
	ret = target_write_u8(target, info->io_base + SH_QSPI_SPDCR, 0x00);
	if (ret != ERROR_OK)
		return ret;

	/* Set clock delay value */
	ret = target_write_u8(target, info->io_base + SH_QSPI_SPCKD, 0x00);
	if (ret != ERROR_OK)
		return ret;

	/* Set SSL negation delay value */
	ret = target_write_u8(target, info->io_base + SH_QSPI_SSLND, 0x00);
	if (ret != ERROR_OK)
		return ret;

	/* Set next-access delay value */
	ret = target_write_u8(target, info->io_base + SH_QSPI_SPND, 0x00);
	if (ret != ERROR_OK)
		return ret;

	/* Set equence command */
	ret = target_write_u16(target, info->io_base + SH_QSPI_SPCMD0,
			       SPCMD_INIT2);
	if (ret != ERROR_OK)
		return ret;

	/* Reset transfer and receive Buffer */
	ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
	if (ret != ERROR_OK)
		return ret;

	val |= SPBFCR_TXRST | SPBFCR_RXRST;

	ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
	if (ret != ERROR_OK)
		return ret;

	/* Clear transfer and receive Buffer control bit */
	ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
	if (ret != ERROR_OK)
		return ret;

	val &= ~(SPBFCR_TXRST | SPBFCR_RXRST);

	ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
	if (ret != ERROR_OK)
		return ret;

	/* Set equence control method. Use equence0 only */
	ret = target_write_u8(target, info->io_base + SH_QSPI_SPSCR, 0x00);
	if (ret != ERROR_OK)
		return ret;

	/* Enable SPI function */
	ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val);
	if (ret != ERROR_OK)
		return ret;

	val |= SPCR_SPE;

	return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val);
}

SPI相关

内置了很多型号的spi flash的操作指令码及参数可以根据型号直接使用:

// SPDX-License-Identifier: GPL-2.0-or-later

/***************************************************************************
 *   Copyright (C) 2018 by Andreas Bolsch                                  *
 *   andreas.bolsch@mni.thm.de                                             *
 *                                                                         *
 *   Copyright (C) 2012 by George Harris                                   *
 *   george@luminairecoffee.com                                            *
 *                                                                         *
 *   Copyright (C) 2010 by Antonio Borneo                                  *
 *   borneo.antonio@gmail.com                                              *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "imp.h"
#include "spi.h"
#include <jtag/jtag.h>

 /* Shared table of known SPI flash devices for SPI-based flash drivers. Taken
  * from device datasheets and Linux SPI flash drivers. */
const struct flash_device flash_devices[] = {
	/* Note: device_id is usually 3 bytes long, however the unused highest byte counts
	 * continuation codes for manufacturer id as per JEP106xx.
	 *
	 * All sizes (page, sector/block and flash) are in bytes.
	 *
	 * Guide to select a proper erase command (if both sector and block erase cmds are available):
	 * Use 4kbit sector erase cmd and set erase size to the size of sector for small devices
	 * (4Mbit and less, size <= 0x80000) to prevent too raw erase granularity.
	 * Use 64kbit block erase cmd and set erase size to the size of block for bigger devices
	 * (8Mbit and more, size >= 0x100000) to keep erase speed reasonable.
	 * If the device implements also 32kbit block erase, use it for 8Mbit, size == 0x100000.
	 */
	/*        name                  read qread  page  erase chip  device_id   page   erase   flash
	 *                              _cmd _cmd   _prog _cmd* _erase            size   size*   size
	 *                                          _cmd        _cmd
	 */
	FLASH_ID("st m25pe10",          0x03, 0x00, 0x02, 0xd8, 0x00, 0x00118020, 0x100, 0x10000, 0x20000),
	FLASH_ID("st m25pe20",          0x03, 0x00, 0x02, 0xd8, 0x00, 0x00128020, 0x100, 0x10000, 0x40000),
	FLASH_ID("st m25pe40",          0x03, 0x00, 0x02, 0xd8, 0x00, 0x00138020, 0x100, 0x10000, 0x80000),
	FLASH_ID("st m25pe80",          0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00148020, 0x100, 0x10000, 0x100000),
	FLASH_ID("st m25pe16",          0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00158020, 0x100, 0x10000, 0x200000),
	FLASH_ID("st m25p05",           0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00102020, 0x80,  0x8000,  0x10000),
	FLASH_ID("st m25p10",           0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00112020, 0x80,  0x8000,  0x20000),
	FLASH_ID("st m25p20",           0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000),
	FLASH_ID("st m25p40",           0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00132020, 0x100, 0x10000, 0x80000),
	FLASH_ID("st m25p80",           0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00142020, 0x100, 0x10000, 0x100000),
	FLASH_ID("st m25p16",           0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00152020, 0x100, 0x10000, 0x200000),
	FLASH_ID("st m25p32",           0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00162020, 0x100, 0x10000, 0x400000),
	FLASH_ID("st m25p64",           0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00172020, 0x100, 0x10000, 0x800000),
	FLASH_ID("st m25p128",          0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00182020, 0x100, 0x40000, 0x1000000),
	FLASH_ID("st m45pe10",          0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00114020, 0x100, 0x10000, 0x20000),
	FLASH_ID("st m45pe20",          0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00124020, 0x100, 0x10000, 0x40000),
	FLASH_ID("st m45pe40",          0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00134020, 0x100, 0x10000, 0x80000),
	FLASH_ID("st m45pe80",          0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00144020, 0x100, 0x10000, 0x100000),
	FLASH_ID("sp s25fl004",         0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00120201, 0x100, 0x10000, 0x80000),
	FLASH_ID("sp s25fl008",         0x03, 0x08, 0x02, 0xd8, 0xc7, 0x00130201, 0x100, 0x10000, 0x100000),
	FLASH_ID("sp s25fl016",         0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00140201, 0x100, 0x10000, 0x200000),
	FLASH_ID("sp s25fl116k",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00154001, 0x100, 0x10000, 0x200000),
	FLASH_ID("sp s25fl032",         0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00150201, 0x100, 0x10000, 0x400000),
	FLASH_ID("sp s25fl132k",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00164001, 0x100, 0x10000, 0x400000),
	FLASH_ID("sp s25fl064",         0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00160201, 0x100, 0x10000, 0x800000),
	FLASH_ID("sp s25fl164k",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00174001, 0x100, 0x10000, 0x800000),
	FLASH_ID("sp s25fl128s",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00182001, 0x100, 0x10000, 0x1000000),
	FLASH_ID("sp s25fl256s",        0x13, 0x00, 0x12, 0xdc, 0xc7, 0x00190201, 0x100, 0x10000, 0x2000000),
	FLASH_ID("sp s25fl512s",        0x13, 0x00, 0x12, 0xdc, 0xc7, 0x00200201, 0x200, 0x40000, 0x4000000),
	FLASH_ID("cyp s25fl064l",       0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00176001, 0x100, 0x10000, 0x800000),
	FLASH_ID("cyp s25fl128l",       0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00186001, 0x100, 0x10000, 0x1000000),
	FLASH_ID("cyp s25fl256l",       0x13, 0x00, 0x12, 0xdc, 0xc7, 0x00196001, 0x100, 0x10000, 0x2000000),
	FLASH_ID("cyp s28hl256t",       0x13, 0xec, 0x12, 0xdc, 0xc7, 0x00195a34, 0x100, 0x40000, 0x2000000), /* page! */
	FLASH_ID("cyp s28hs256t",       0x13, 0xec, 0x12, 0xdc, 0xc7, 0x00195b34, 0x100, 0x40000, 0x2000000), /* page! */
	FLASH_ID("cyp s28hl512t",       0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a5a34, 0x100, 0x40000, 0x4000000), /* page! */
	FLASH_ID("cyp s28hs512t",       0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a5b34, 0x100, 0x40000, 0x4000000), /* page! */
	FLASH_ID("cyp s28hl01gt",       0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001b5a34, 0x100, 0x40000, 0x8000000), /* page! */
	FLASH_ID("cyp s28hs01gt",       0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001b5b34, 0x100, 0x40000, 0x8000000), /* page! */
	FLASH_ID("atmel 25f512",        0x03, 0x00, 0x02, 0x52, 0xc7, 0x0065001f, 0x80,  0x8000,  0x10000),
	FLASH_ID("atmel 25f1024",       0x03, 0x00, 0x02, 0x52, 0x62, 0x0060001f, 0x100, 0x8000,  0x20000),
	FLASH_ID("atmel 25f2048",       0x03, 0x00, 0x02, 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000),
	FLASH_ID("atmel 25f4096",       0x03, 0x00, 0x02, 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000),
	FLASH_ID("atmel 25fs040",       0x03, 0x00, 0x02, 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000),
	FLASH_ID("adesto 25sf041b",     0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001841f, 0x100, 0x10000, 0x80000),
	FLASH_ID("adesto 25df081a",     0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001451f, 0x100, 0x10000, 0x100000),
	FLASH_ID("adesto 25sf081b",     0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001851f, 0x100, 0x10000, 0x100000),
	FLASH_ID("adesto 25sf161b",     0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001861f, 0x100, 0x10000, 0x200000),
	FLASH_ID("adesto 25df321b",     0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001471f, 0x100, 0x10000, 0x400000),
	FLASH_ID("adesto 25sf321b",     0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001871f, 0x100, 0x10000, 0x400000),
	FLASH_ID("adesto 25xf641b",     0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001881f, 0x100, 0x10000, 0x800000), /* sf/qf */
	FLASH_ID("adesto 25xf128a",     0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001891f, 0x100, 0x10000, 0x1000000), /* sf/qf */
	FLASH_ID("adesto xp032",        0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0700a743, 0x100, 0x10000, 0x400000), /* 4-byte */
	FLASH_ID("adesto xp064b",       0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0001a81f, 0x100, 0x10000, 0x800000), /* 4-byte */
	FLASH_ID("adesto xp128",        0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0000a91f, 0x100, 0x10000, 0x1000000), /* 4-byte */
	FLASH_ID("mac 25l512",          0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000),
	FLASH_ID("mac 25l1005",         0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000),
	FLASH_ID("mac 25l2005",         0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000),
	FLASH_ID("mac 25l4005",         0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001320c2, 0x010, 0x10000, 0x80000),
	FLASH_ID("mac 25l8005",         0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001420c2, 0x010, 0x10000, 0x100000),
	FLASH_ID("mac 25l1605",         0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001520c2, 0x100, 0x10000, 0x200000),
	FLASH_ID("mac 25l3205",         0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001620c2, 0x100, 0x10000, 0x400000),
	FLASH_ID("mac 25l6405",         0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001720c2, 0x100, 0x10000, 0x800000),
	FLASH_ID("mac 25l12845",        0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001820c2, 0x100, 0x10000, 0x1000000),
	FLASH_ID("mac 25l25645",        0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001920c2, 0x100, 0x10000, 0x2000000),
	FLASH_ID("mac 25l51245",        0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a20c2, 0x100, 0x10000, 0x4000000),
	FLASH_ID("mac 25lm51245",       0x13, 0xec, 0x12, 0xdc, 0xc7, 0x003a85c2, 0x100, 0x10000, 0x4000000),
	FLASH_ID("mac 25r512f",         0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001028c2, 0x100, 0x10000, 0x10000),
	FLASH_ID("mac 25r1035f",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001128c2, 0x100, 0x10000, 0x20000),
	FLASH_ID("mac 25r2035f",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001228c2, 0x100, 0x10000, 0x40000),
	FLASH_ID("mac 25r4035f",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001328c2, 0x100, 0x10000, 0x80000),
	FLASH_ID("mac 25r8035f",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001428c2, 0x100, 0x10000, 0x100000),
	FLASH_ID("mac 25r1635f",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001528c2, 0x100, 0x10000, 0x200000),
	FLASH_ID("mac 25r3235f",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001628c2, 0x100, 0x10000, 0x400000),
	FLASH_ID("mac 25r6435f",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001728c2, 0x100, 0x10000, 0x800000),
	FLASH_ID("mac 25u1635e",        0x03, 0xeb, 0x02, 0x20, 0xc7, 0x003525c2, 0x100, 0x1000,  0x100000),
	FLASH_ID("mac 66l1g45g",        0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001b20c2, 0x100, 0x10000, 0x8000000),
	FLASH_ID("mac 66um1g45g",       0x13, 0xec, 0x12, 0xdc, 0xc7, 0x003b80c2, 0x100, 0x10000, 0x8000000),
	FLASH_ID("mac 66lm1g45g",       0x13, 0xec, 0x12, 0xdc, 0xc7, 0x003b85c2, 0x100, 0x10000, 0x8000000),
	FLASH_ID("micron n25q032",      0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0016ba20, 0x100, 0x10000, 0x400000),
	FLASH_ID("micron n25q064",      0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000),
	FLASH_ID("micron n25q128",      0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000),
	FLASH_ID("micron n25q256 3v",   0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019ba20, 0x100, 0x10000, 0x2000000),
	FLASH_ID("micron n25q256 1.8v", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019bb20, 0x100, 0x10000, 0x2000000),
	FLASH_ID("micron mt25ql512",    0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0020ba20, 0x100, 0x10000, 0x4000000),
	FLASH_ID("micron mt25ql01",     0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0021ba20, 0x100, 0x10000, 0x8000000),
	FLASH_ID("micron mt25qu01",     0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0021bb20, 0x100, 0x10000, 0x8000000),
	FLASH_ID("micron mt25ql02",     0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0022ba20, 0x100, 0x10000, 0x10000000),
	FLASH_ID("win w25q80bv",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000),
	FLASH_ID("win w25q16jv",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001540ef, 0x100, 0x10000, 0x200000),
	FLASH_ID("win w25q16jv",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001570ef, 0x100, 0x10000, 0x200000), /* QPI / DTR */
	FLASH_ID("win w25q32fv/jv",     0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000),
	FLASH_ID("win w25q32fv",        0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000), /* QPI mode */
	FLASH_ID("win w25q32jv",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001670ef, 0x100, 0x10000, 0x400000),
	FLASH_ID("win w25q64fv/jv",     0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000),
	FLASH_ID("win w25q64fv",        0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001760ef, 0x100, 0x10000, 0x800000), /* QPI mode */
	FLASH_ID("win w25q64jv",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001770ef, 0x100, 0x10000, 0x800000),
	FLASH_ID("win w25q128fv/jv",    0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001840ef, 0x100, 0x10000, 0x1000000),
	FLASH_ID("win w25q128fv",       0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001860ef, 0x100, 0x10000, 0x1000000), /* QPI mode */
	FLASH_ID("win w25q128jv",       0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001870ef, 0x100, 0x10000, 0x1000000),
	FLASH_ID("win w25q256fv/jv",    0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001940ef, 0x100, 0x10000, 0x2000000),
	FLASH_ID("win w25q256fv",       0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001960ef, 0x100, 0x10000, 0x2000000), /* QPI mode */
	FLASH_ID("win w25q256jv",       0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001970ef, 0x100, 0x10000, 0x2000000),
	FLASH_ID("win w25q512jv",       0x03, 0x00, 0x02, 0xd8, 0xc7, 0x002040ef, 0x100, 0x10000, 0x4000000),
	FLASH_ID("win w25q01jv",        0x13, 0x00, 0x12, 0xdc, 0xc7, 0x002140ef, 0x100, 0x10000, 0x8000000),
	FLASH_ID("win w25q01jv-dtr",    0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x002170ef, 0x100, 0x10000, 0x8000000),
	FLASH_ID("win w25q02jv-dtr",    0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x002270ef, 0x100, 0x10000, 0x10000000),
	FLASH_ID("gd gd25q512",         0x03, 0x00, 0x02, 0x20, 0xc7, 0x001040c8, 0x100, 0x1000,  0x10000),
	FLASH_ID("gd gd25q10",          0x03, 0x00, 0x02, 0x20, 0xc7, 0x001140c8, 0x100, 0x1000,  0x20000),
	FLASH_ID("gd gd25q20",          0x03, 0x00, 0x02, 0x20, 0xc7, 0x001240c8, 0x100, 0x1000,  0x40000),
	FLASH_ID("gd gd25q40",          0x03, 0x00, 0x02, 0x20, 0xc7, 0x001340c8, 0x100, 0x1000,  0x80000),
	FLASH_ID("gd gd25q16c",         0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000),
	FLASH_ID("gd gd25q32c",         0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000),
	FLASH_ID("gd gd25q64c",         0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001740c8, 0x100, 0x10000, 0x800000),
	FLASH_ID("gd gd25q128c",        0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000),
	FLASH_ID("gd gd25q256c",        0x13, 0x00, 0x12, 0xdc, 0xc7, 0x001940c8, 0x100, 0x10000, 0x2000000),
	FLASH_ID("gd gd25q512mc",       0x13, 0x00, 0x12, 0xdc, 0xc7, 0x002040c8, 0x100, 0x10000, 0x4000000),
	FLASH_ID("gd gd25lx256e",       0x13, 0x0c, 0x12, 0xdc, 0xc7, 0x001968c8, 0x100, 0x10000, 0x2000000),
	FLASH_ID("zbit zb25vq16",       0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0015605e, 0x100, 0x10000, 0x200000),
	FLASH_ID("zbit zb25vq32",       0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016405e, 0x100, 0x10000, 0x400000),
	FLASH_ID("zbit zb25vq32",       0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016605e, 0x100, 0x10000, 0x400000), /* QPI mode */
	FLASH_ID("zbit zb25vq64",       0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017405e, 0x100, 0x10000, 0x800000),
	FLASH_ID("zbit zb25vq64",       0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017605e, 0x100, 0x10000, 0x800000), /* QPI mode */
	FLASH_ID("zbit zb25vq128",      0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018405e, 0x100, 0x10000, 0x1000000),
	FLASH_ID("zbit zb25vq128",      0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018605e, 0x100, 0x10000, 0x1000000), /* QPI mode */
	FLASH_ID("issi is25lq040b",     0x03, 0xeb, 0x02, 0x20, 0xc7, 0x0013409d, 0x100, 0x1000,  0x80000),
	FLASH_ID("issi is25lp032",      0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0016609d, 0x100, 0x10000, 0x400000),
	FLASH_ID("issi is25lp064",      0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0017609d, 0x100, 0x10000, 0x800000),
	FLASH_ID("issi is25lp128d",     0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018609d, 0x100, 0x10000, 0x1000000),
	FLASH_ID("issi is25wp128d",     0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018709d, 0x100, 0x10000, 0x1000000),
	FLASH_ID("issi is25lp256d",     0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019609d, 0x100, 0x10000, 0x2000000),
	FLASH_ID("issi is25wp256d",     0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019709d, 0x100, 0x10000, 0x2000000),
	FLASH_ID("issi is25lp512m",     0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a609d, 0x100, 0x10000, 0x4000000),
	FLASH_ID("issi is25wp512m",     0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a709d, 0x100, 0x10000, 0x4000000),
	FLASH_ID("xtx xt25f02e",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0012400b, 0x100, 0x10000, 0x40000),
	FLASH_ID("xtx xt25f04d",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0013400b, 0x100, 0x10000, 0x80000),
	FLASH_ID("xtx xt25f08b",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0014400b, 0x100, 0x10000, 0x100000),
	FLASH_ID("xtx xt25f16b",        0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0015400b, 0x100, 0x10000, 0x200000),
	FLASH_ID("xtx xt25f32b",        0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016400b, 0x100, 0x10000, 0x200000),
	FLASH_ID("xtx xt25f64b",        0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017400b, 0x100, 0x10000, 0x400000),
	FLASH_ID("xtx xt25f128b",       0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018400b, 0x100, 0x10000, 0x800000),
	FLASH_ID("xtx xt25q08d",        0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0014600b, 0x100, 0x10000, 0x100000),
	FLASH_ID("xtx xt25q16b",        0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0015600b, 0x100, 0x10000, 0x200000),
	FLASH_ID("xtx xt25q32b",        0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016600b, 0x100, 0x10000, 0x400000), /* exists ? */
	FLASH_ID("xtx xt25q64b",        0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017600b, 0x100, 0x10000, 0x800000),
	FLASH_ID("xtx xt25q128b",       0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018600b, 0x100, 0x10000, 0x1000000),
	FLASH_ID("zetta zd25q16",       0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001560ba, 0x100, 0x10000, 0x200000),

	/* FRAM, no erase commands, no write page or sectors */

	/*        name                  read qread  page  device_id   total
	 *                              _cmd _cmd   _prog             size
	 *                                          _cmd
	 */
	FRAM_ID("fu mb85rs16n",         0x03, 0,    0x02, 0x00010104, 0x800),
	FRAM_ID("fu mb85rs32v",         0x03, 0,    0x02, 0x00010204, 0x1000), /* exists ? */
	FRAM_ID("fu mb85rs64v",         0x03, 0,    0x02, 0x00020304, 0x2000),
	FRAM_ID("fu mb85rs128b",        0x03, 0,    0x02, 0x00090404, 0x4000),
	FRAM_ID("fu mb85rs256b",        0x03, 0,    0x02, 0x00090504, 0x8000),
	FRAM_ID("fu mb85rs512t",        0x03, 0,    0x02, 0x00032604, 0x10000),
	FRAM_ID("fu mb85rs1mt",         0x03, 0,    0x02, 0x00032704, 0x20000),
	FRAM_ID("fu mb85rs2mta",        0x03, 0,    0x02, 0x00034804, 0x40000),
	FRAM_ID("cyp fm25v01a",         0x03, 0,    0x02, 0x060821c2, 0x4000),
	FRAM_ID("cyp fm25v02",          0x03, 0,    0x02, 0x060022c2, 0x8000),
	FRAM_ID("cyp fm25v02a",         0x03, 0,    0x02, 0x060822c2, 0x8000),
	FRAM_ID("cyp fm25v05",          0x03, 0,    0x02, 0x060023c2, 0x10000),
	FRAM_ID("cyp fm25v10",          0x03, 0,    0x02, 0x060024c2, 0x20000),
	FRAM_ID("cyp fm25v20a",         0x03, 0,    0x02, 0x060825c2, 0x40000),
	FRAM_ID("cyp fm25v40",          0x03, 0,    0x02, 0x064026c2, 0x80000),
	FRAM_ID("cyp cy15b102qn",       0x03, 0,    0x02, 0x06002ac2, 0x40000),
	FRAM_ID("cyp cy15v102qn",       0x03, 0,    0x02, 0x06042ac2, 0x40000),
	FRAM_ID("cyp cy15b104qi",       0x03, 0,    0x02, 0x06012dc2, 0x80000),
	FRAM_ID("cyp cy15b104qi",       0x03, 0,    0x02, 0x06a12dc2, 0x80000),
	FRAM_ID("cyp cy15v104qi",       0x03, 0,    0x02, 0x06052dc2, 0x80000),
	FRAM_ID("cyp cy15v104qi",       0x03, 0,    0x02, 0x06a52dc2, 0x80000),
	FRAM_ID("cyp cy15b104qn",       0x03, 0,    0x02, 0x06402cc2, 0x80000),
	FRAM_ID("cyp cy15b108qi",       0x03, 0,    0x02, 0x06012fc2, 0x100000),
	FRAM_ID("cyp cy15b108qi",       0x03, 0,    0x02, 0x06a12fc2, 0x100000),
	FRAM_ID("cyp cy15v108qi",       0x03, 0,    0x02, 0x06052fc2, 0x100000),
	FRAM_ID("cyp cy15v108qi",       0x03, 0,    0x02, 0x06a52fc2, 0x100000),
	FRAM_ID("cyp cy15b108qn",       0x03, 0,    0x02, 0x06012ec2, 0x100000),
	FRAM_ID("cyp cy15b108qn",       0x03, 0,    0x02, 0x06032ec2, 0x100000),
	FRAM_ID("cyp cy15b108qn",       0x03, 0,    0x02, 0x06a12ec2, 0x100000),
	FRAM_ID("cyp cy15v108qn",       0x03, 0,    0x02, 0x06052ec2, 0x100000),
	FRAM_ID("cyp cy15v108qn",       0x03, 0,    0x02, 0x06072ec2, 0x100000),
	FRAM_ID("cyp cy15v108qn",       0x03, 0,    0x02, 0x06a52ec2, 0x100000),

	FLASH_ID(NULL,                  0,    0,    0,    0,    0,    0,          0,     0,       0)
};