Definition of Uboot spi-nor device information and understanding of 3-address mode and 4-address mode

1. Device support

When using a new spi-nor device, you must first know the manufacturer and ID of your device, so that you can do specific menuconfig device support. The specific menuconfig configuration path is as follows, find the corresponding device manufacturer's SPI FLASH and open it .

 Location:                                                                                                                                                                                                                          │
  │    -> Device Drivers                                                                                                                                                                                                                │
  │       -> MTD Support                                                                                                                                                                                                                 │
  │          -> SPI Flash Support

insert image description here
If it is a domestic device or other manufacturer's device, if it is not supported in menuconfig, you can manually add the device.
The adding location is located in: uboot\drivers\mtd\spi path, in the spi-nor-ids.c file, all device information related to the spi device is described here. Different manufacturers use different macro definitions to open it, so it needs to be configured in menuconfig.

const struct flash_info spi_nor_ids[] = {
    
    
#ifdef CONFIG_SPI_FLASH_ATMEL		/* ATMEL */
	/* Atmel -- some are (confusingly) marketed as "DataFlash" */
	{
    
     INFO("at26df321",	0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
	{
    
     INFO("at25df321a",	0x1f4701, 0, 64 * 1024, 64, SECT_4K) },

	{
    
     INFO("at45db011d",	0x1f2200, 0, 64 * 1024,   4, SECT_4K) },
	{
    
     INFO("at45db021d",	0x1f2300, 0, 64 * 1024,   8, SECT_4K) },
	{
    
     INFO("at45db041d",	0x1f2400, 0, 64 * 1024,   8, SECT_4K) },
	{
    
     INFO("at45db081d",	0x1f2500, 0, 64 * 1024,  16, SECT_4K) },
	{
    
     INFO("at45db161d",	0x1f2600, 0, 64 * 1024,  32, SECT_4K) },
	{
    
     INFO("at45db321d",	0x1f2700, 0, 64 * 1024,  64, SECT_4K) },
	{
    
     INFO("at45db641d",	0x1f2800, 0, 64 * 1024, 128, SECT_4K) },
	{
    
     INFO("at26df081a", 	0x1f4501, 0, 64 * 1024,  16, SECT_4K) },
#endif
#ifdef CONFIG_SPI_FLASH_STMICRO		/* STMICRO */
	/* Micron */
	{
    
     INFO("n25q016a",	 0x20bb15, 0, 64 * 1024,   32, SECT_4K | SPI_NOR_QUAD_READ) },
	{
    
     INFO("n25q032",	 0x20ba16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
	{
    
     INFO("n25q032a",	0x20bb16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
	{
    
     INFO("n25q064",     0x20ba17, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_QUAD_READ) },
	{
    
     INFO("n25q064a",    0x20bb17, 0, 64 * 1024,  128, SECT_4K | SPI_NOR_QUAD_READ) },
	{
    
     INFO("n25q128a11",  0x20bb18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
	{
    
     INFO("n25q128a13",  0x20ba18, 0, 64 * 1024,  256, SECT_4K | SPI_NOR_QUAD_READ) },
	{
    
     INFO("n25q256a",    0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
	{
    
     INFO("n25q256ax1",  0x20bb19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ ) },
	{
    
     INFO("n25q512a",    0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
	{
    
     INFO("n25q512ax3",  0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
	{
    
     INFO("n25q00",      0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
	{
    
     INFO("n25q00a",     0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
	{
    
     INFO("mt25qu02g",   0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },

	{
    
     INFO("SM25QH256M",  0x206019, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },


#endif
	{
    
    ......}//还有很多
}

SPI FLASH ids device information description

To distinguish the specific configuration information of the device, in addition to understanding the attributes of the device in the user manual, you also need to understand how to define the attributes of a device in the code. Let's look at INFO first, the definition of this macro:

#define INFO(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
		INFO_NAME(_name)					\
		.id = {
      
      							\
			((_jedec_id) >> 16) & 0xff,			\
			((_jedec_id) >> 8) & 0xff,			\
			(_jedec_id) & 0xff,				\
			((_ext_id) >> 8) & 0xff,			\
			(_ext_id) & 0xff,				\
			},						\
		.id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))),	\
		.sector_size = (_sector_size),				\
		.n_sectors = (_n_sectors),				\
		.page_size = 256,					\
		.flags = (_flags),

Refer to the existing ones above and compare them one by one

  • _name: device name
  • _jedec_id : The ID of the device (in the code, the actual matching id)
  • _ext_id: extension id (it should be, I don’t know how to use it, how to define it)
  • _sector_size: sector size, (32k/64k)
  • _n_sectors: the number of sectors, (the sector size and the number of sectors can calculate the sector capacity)
  • _flags : Used to define device capabilities.
#define SECT_4K			BIT(0)	/* SPINOR_OP_BE_4K works uniformly */
#define SPI_NOR_NO_ERASE	BIT(1)	/* No erase command needed */
#define SST_WRITE		BIT(2)	/* use SST byte programming */
#define SPI_NOR_NO_FR		BIT(3)	/* Can't do fastread */
#define SECT_4K_PMC		BIT(4)	/* SPINOR_OP_BE_4K_PMC works uniformly */
#define SPI_NOR_DUAL_READ	BIT(5)	/* Flash supports Dual Read */
#define SPI_NOR_QUAD_READ	BIT(6)	/* Flash supports Quad Read */
#define USE_FSR			BIT(7)	/* use flag status register */
#define SPI_NOR_HAS_LOCK	BIT(8)	/* Flash supports lock/unlock via SR */
#define SPI_NOR_HAS_TB		BIT(9)	/*
					 * Flash SR has Top/Bottom (TB) protect
					 * bit. Must be used with
					 * SPI_NOR_HAS_LOCK.
					 */
#define	SPI_S3AN		BIT(10)	/*
					 * Xilinx Spartan 3AN In-System Flash
					 * (MFR cannot be used for probing
					 * because it has the same value as
					 * ATMEL flashes)
					 */
#define SPI_NOR_4B_OPCODES	BIT(11)	/*
					 * Use dedicated 4byte address op codes
					 * to support memory size above 128Mib. 16MB
					 */
#define NO_CHIP_ERASE		BIT(12) /* Chip does not support chip erase */
#define SPI_NOR_SKIP_SFDP	BIT(13)	/* Skip parsing of SFDP tables */
#define USE_CLSR		BIT(14)	/* use CLSR command */

The above macros can be used to define the flag attribute, select a few more commonly used ones for explanation:

  • SECT_4K:
    4k erasing, SPI flash generally supports three erasing methods: erasing by sector, erasing by block, and erasing the entire chip. Performance comparison: Fast erase time: 30ms (typ.)/sector (4K-byte per sector); 0.25s(typ.) /block (64K-byte per block); 10s(typ.) / chip. From the above data, in the case of erasing the same size, the execution time is sector>block>chip
    , erasing by sector, it takes 0.48s to erase 64K, and it only takes 0.25s to erase 64K by block; erase by block, It takes 16s to erase a complete chip, but it only takes 10s to erase and write by chip; it takes 30s to erase and write a complete chip by sector.
  • SPI_NOR_DUAL_READ, SPI_NOR_QUAD_READ
    are used to specify the transmission mode of SPI
    1. Standard SPI
      Standard SPI is usually called SPI. It is a serial peripheral interface specification with 4 pin signals: clk, cs, mosi, miso
    2. Dual SPI
      is only for SPI Flash, not for all SPI peripherals. For SPI Flash, full-duplex is not commonly used, so the usage of mosi and miso is expanded to allow them to work in half-duplex to double data transmission. That is to say, for Dual SPI Flash, you can send a command byte to enter dual mode, so that mosi becomes SIO0 (serial io 0), and mosi becomes SIO1 (serial io 1), so that 2 bits of data can be transmitted within one clock cycle , doubling the data transfer
    3. Qual SPI
      is similar to Dual SPI, and it is also for SPI Flash. Qual SPI Flash adds two I/O lines (SIO2, SIO3), the purpose is to transmit 4 bits in one clock, so for SPI Flash, there are standard spi flash, dual
      spi , qual spi Three types, corresponding to 3-wire, 4-wire, 6-wire respectively, under the same clock, the more wires, the higher the transmission rate.
  • Whether SPI_NOR_4B_OPCODES
    uses 4-address opcodes, note that this is not to specify the use of 4-address mode, but to enable the operation command of whether to use 4-address. If this property is turned on, then 3-address opcodes are converted to 4-address opcodes. If it is not enabled, and if the flash capacity is greater than 128Mb or 16MB, then the 4-address mode will be enabled, which will be explained in the code later.

SPI Nor Flash initialization

The following codes are explained based on uboot image.
spi-nor-core.c

int spi_nor_scan(struct spi_nor *nor)
{
    
    
	struct spi_nor_flash_parameter params;
	const struct flash_info *info = NULL;
	struct mtd_info *mtd = &nor->mtd;
	struct spi_nor_hwcaps hwcaps = {
    
    
		.mask = SNOR_HWCAPS_READ |
			SNOR_HWCAPS_READ_FAST |
			SNOR_HWCAPS_PP,
	};
	struct spi_slave *spi = nor->spi;
	int ret;

	/* Reset SPI protocol for all commands. */
	nor->reg_proto = SNOR_PROTO_1_1_1;
	nor->read_proto = SNOR_PROTO_1_1_1;
	nor->write_proto = SNOR_PROTO_1_1_1;
	nor->read = spi_nor_read_data;
	nor->write = spi_nor_write_data;
	nor->read_reg = spi_nor_read_reg;
	nor->write_reg = spi_nor_write_reg;

	if (spi->mode & SPI_RX_QUAD) {
    
    
		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;

		if (spi->mode & SPI_TX_QUAD)
			hwcaps.mask |= (SNOR_HWCAPS_READ_1_4_4 |
					SNOR_HWCAPS_PP_1_1_4 |
					SNOR_HWCAPS_PP_1_4_4);
	} else if (spi->mode & SPI_RX_DUAL) {
    
    
		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;

		if (spi->mode & SPI_TX_DUAL)
			hwcaps.mask |= SNOR_HWCAPS_READ_1_2_2;
	}

	info = spi_nor_read_id(nor);
	if (IS_ERR_OR_NULL(info))
		return -ENOENT;
	/* Parse the Serial Flash Discoverable Parameters table. */
	ret = spi_nor_init_params(nor, info, &params);
	if (ret)
		return ret;

	if (!mtd->name)
		mtd->name = info->name;
	mtd->priv = nor;
	mtd->type = MTD_NORFLASH;
	mtd->writesize = 1;
	mtd->flags = MTD_CAP_NORFLASH;
	mtd->size = params.size;
	mtd->_erase = spi_nor_erase;
	mtd->_read = spi_nor_read;

#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
	/* NOR protection support for STmicro/Micron chips and similar */
	if (JEDEC_MFR(info) == SNOR_MFR_ST ||
	    JEDEC_MFR(info) == SNOR_MFR_MICRON ||
	    JEDEC_MFR(info) == SNOR_MFR_SST ||
			info->flags & SPI_NOR_HAS_LOCK) {
    
    
		nor->flash_lock = stm_lock;
		nor->flash_unlock = stm_unlock;
		nor->flash_is_locked = stm_is_locked;
	}
#endif

#ifdef CONFIG_SPI_FLASH_SST
	/* sst nor chips use AAI word program */
	if (info->flags & SST_WRITE)
		mtd->_write = sst_write;
	else
#endif
		mtd->_write = spi_nor_write;

	if (info->flags & USE_FSR)
		nor->flags |= SNOR_F_USE_FSR;
	if (info->flags & SPI_NOR_HAS_TB)
		nor->flags |= SNOR_F_HAS_SR_TB;
	if (info->flags & NO_CHIP_ERASE)
		nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
	if (info->flags & USE_CLSR)
		nor->flags |= SNOR_F_USE_CLSR;

	if (info->flags & SPI_NOR_NO_ERASE)
		mtd->flags |= MTD_NO_ERASE;

	nor->page_size = params.page_size;
	mtd->writebufsize = nor->page_size;

	/* Some devices cannot do fast-read, no matter what DT tells us */
	if ((info->flags & SPI_NOR_NO_FR) || (spi->mode & SPI_RX_SLOW))
		params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;

	/*
	 * Configure the SPI memory:
	 * - select op codes for (Fast) Read, Page Program and Sector Erase.
	 * - set the number of dummy cycles (mode cycles + wait states).
	 * - set the SPI protocols for register and memory accesses.
	 * - set the Quad Enable bit if needed (required by SPI x-y-4 protos).
	 */
	ret = spi_nor_setup(nor, info, &params, &hwcaps);
	if (ret)
		return ret;

	if (nor->addr_width) {
    
    
		/* already configured from SFDP */
	} else if (info->addr_width) {
    
    
		nor->addr_width = info->addr_width;
	} else if (mtd->size > SZ_16M) {
    
    
#ifndef CONFIG_SPI_FLASH_BAR
		/* enable 4-byte addressing if the device exceeds 16MiB */
		nor->addr_width = 4;
		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || info->flags & SPI_NOR_4B_OPCODES)
		{
    
    
			spi_nor_set_4byte_opcodes(nor, info);
			dev_err(nor->dev, "spi_nor_set_4byte_opcodes s:	0x%x\n",(info->flags & SPI_NOR_4B_OPCODES) );
		}
#else
	/* Configure the BAR - discover bank cmds and read current bank */
	nor->addr_width = 3;
	ret = read_bar(nor, info);
	if (ret < 0)
		return ret;
#endif
	} else {
    
    
		nor->addr_width = 3;
	}

	if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) {
    
    
		dev_dbg(dev, "address width is too large: %u\n",
			nor->addr_width);
		return -EINVAL;
	}

	/* Send all the required SPI flash commands to initialize device */
	nor->info = info;
	ret = spi_nor_init(nor);
	if (ret)
		return ret;

	nor->name = mtd->name;
	nor->size = mtd->size;
	nor->erase_size = mtd->erasesize;
	nor->sector_size = mtd->erasesize;

#ifndef CONFIG_SPL_BUILD
	printf("SF: Detected %s with page size ", nor->name);
	print_size(nor->page_size, ", erase size ");
	print_size(nor->erase_size, ", total ");
	print_size(nor->size, "");
	puts("\n");
#endif

	return 0;
}

The above code is triggered by the user calling the sf probe command in uboot mode. Its main functions are the function initialization assignment of the device handle, device detection, function configuration, device initialization, etc.

  1. Device Detection
    Device detection info = spi_nor_read_id(nor);is implemented through functions. The code will read the device ID, and then compare it with the ID in the above device list to determine whether the driver supports it. If it is not found, you can directly judge whether the device exists through the read ID number, and whether menuconfi is needed for configuration. If the read IDs are all 0, then there must be a problem with the wiring of the hardware device, and the ID cannot be read.
static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
{
    
    
	int			tmp;
	u8			id[SPI_NOR_MAX_ID_LEN];
	const struct flash_info	*info;

	tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
	if (tmp < 0) {
    
    
		dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
		return ERR_PTR(tmp);
	}

	info = spi_nor_ids;
	for (; info->name; info++) {
    
    
		if (info->id_len) {
    
    
			if (!memcmp(info->id, id, info->id_len))
				return info;
		}
	}

	dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
		id[0], id[1], id[2]);
	return ERR_PTR(-ENODEV);
}
  1. Judgment of the 4-address opcode of the device
    The code in the figure below is part of the scan function. If the current device capacity is greater than 16MB, then it is necessary to use 4-address to read and write. There are two ways to interact with 4-address. One is: use the 4-address opcode to operate. If the chip does not support 4-address opcodes, then 4-address mode will be used during the initialization phase.
    insert image description here
    insert image description here
    It is difficult to understand here. From the code, we can see that when the INFO information of the device defines the SPI_NOR_4B_OPCODES attribute, it will definitely enter the judgment of three-address conversion to four-address, then it will use different when reading and writing operations. opcode for erase read and write. If this attribute is not defined, the opcode will not be converted, and the 4-address mode will be enabled during the initialization phase.

  2. The uboot sf operation command is used to test whether the 4-address mode is normal.

sf probe
sf erase 0x0 0x10000 /* erase one sector at 0x0 */
sf read 0x21000000  0x0 0x100
md.b 0x21000000
sf erase 0x1000000 0x1000 /* erase one sector at 16M */
sf read 0x22000000  0x0 0x100
md.b 0x22000000

sf write 0x10000000 0x1000000 0x100 /* write a page of data at 16M */
sf read 0x20000000  0x1000000 0x100 /* read back */
md.b 0x20000000

sf read 0x20000000  0x0 0x100
md.b 0x20000000

Guess you like

Origin blog.csdn.net/qq_38505858/article/details/126757889