Commit 773bbe10 authored by Michael Walle's avatar Michael Walle Committed by Tudor Ambarus
Browse files

mtd: spi-nor: add generic flash driver



Our SFDP parsing is everything we need to support all basic operations
of a flash device. If the flash isn't found in our in-kernel flash
database, gracefully fall back to a driver described solely by its SFDP
tables.

Signed-off-by: default avatarMichael Walle <michael@walle.cc>
Signed-off-by: default avatarTudor Ambarus <tudor.ambarus@microchip.com>
Tested-by: default avatarTudor Ambarus <tudor.ambarus@microchip.com>
Reviewed-by: default avatarTakahiro Kuwano <Takahiro.Kuwano@infineon.com>
Link: https://lore.kernel.org/r/20220810220654.1297699-7-michael@walle.cc
parent 39eece67
Loading
Loading
Loading
Loading
+24 −2
Original line number Diff line number Diff line
@@ -1634,6 +1634,16 @@ static const struct spi_nor_manufacturer *manufacturers[] = {
	&spi_nor_xmc,
};

static const struct flash_info spi_nor_generic_flash = {
	.name = "spi-nor-generic",
	/*
	 * JESD216 rev A doesn't specify the page size, therefore we need a
	 * sane default.
	 */
	.page_size = 256,
	.parse_sfdp = true,
};

static const struct flash_info *spi_nor_match_id(struct spi_nor *nor,
						 const u8 *id)
{
@@ -1672,6 +1682,14 @@ static const struct flash_info *spi_nor_detect(struct spi_nor *nor)
		return ERR_PTR(-ENOMEM);

	info = spi_nor_match_id(nor, id);

	/* Fallback to a generic flash described only by its SFDP data. */
	if (!info) {
		ret = spi_nor_check_sfdp_signature(nor);
		if (!ret)
			info = &spi_nor_generic_flash;
	}

	if (!info) {
		dev_err(nor->dev, "unrecognized JEDEC id bytes: %*ph\n",
			SPI_NOR_MAX_ID_LEN, id);
@@ -2098,8 +2116,12 @@ static int spi_nor_select_pp(struct spi_nor *nor,
 * spi_nor_select_uniform_erase() - select optimum uniform erase type
 * @map:		the erase map of the SPI NOR
 * @wanted_size:	the erase type size to search for. Contains the value of
 *			info->sector_size or of the "small sector" size in case
 *			CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is defined.
 *			info->sector_size, the "small sector" size in case
 *			CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is defined or 0 if
 *			there is no information about the sector size. The
 *			latter is the case if the flash parameters are parsed
 *			solely by SFDP, then the largest supported erase type
 *			is selected.
 *
 * Once the optimum uniform sector erase command is found, disable all the
 * other.
+1 −0
Original line number Diff line number Diff line
@@ -701,6 +701,7 @@ int spi_nor_controller_ops_read_reg(struct spi_nor *nor, u8 opcode,
int spi_nor_controller_ops_write_reg(struct spi_nor *nor, u8 opcode,
				     const u8 *buf, size_t len);

int spi_nor_check_sfdp_signature(struct spi_nor *nor);
int spi_nor_parse_sfdp(struct spi_nor *nor);

static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd)
+27 −0
Original line number Diff line number Diff line
@@ -1256,6 +1256,33 @@ static void spi_nor_post_sfdp_fixups(struct spi_nor *nor)
		nor->info->fixups->post_sfdp(nor);
}

/**
 * spi_nor_check_sfdp_signature() - check for a valid SFDP signature
 * @nor:	pointer to a 'struct spi_nor'
 *
 * Used to detect if the flash supports the RDSFDP command as well as the
 * presence of a valid SFDP table.
 *
 * Return: 0 on success, -errno otherwise.
 */
int spi_nor_check_sfdp_signature(struct spi_nor *nor)
{
	u32 signature;
	int err;

	/* Get the SFDP header. */
	err = spi_nor_read_sfdp_dma_unsafe(nor, 0, sizeof(signature),
					   &signature);
	if (err < 0)
		return err;

	/* Check the SFDP signature. */
	if (le32_to_cpu(signature) != SFDP_SIGNATURE)
		return -EINVAL;

	return 0;
}

/**
 * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
 * @nor:		pointer to a 'struct spi_nor'