- spi_nor_read_sfdp_dma_unsafe (Vaishnav)
- w25q01/02 (Jim)
This commit is contained in:
Tom Rini 2023-12-18 09:56:42 -05:00
commit cd908ba186
11 changed files with 210 additions and 7 deletions

View file

@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
spinand-objs := core.o esmt.o gigadevice.o macronix.o micron.o paragon.o
spinand-objs += toshiba.o winbond.o
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o

View file

@ -828,6 +828,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
&paragon_spinand_manufacturer,
&toshiba_spinand_manufacturer,
&winbond_spinand_manufacturer,
&esmt_c8_spinand_manufacturer,
};
static int spinand_manufacturer_match(struct spinand_device *spinand,

137
drivers/mtd/nand/spi/esmt.c Normal file
View file

@ -0,0 +1,137 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Author:
* Chuanhong Guo <gch981213@gmail.com> - the main driver logic
* Martin Kurbanov <mmkurbanov@sberdevices.ru> - OOB layout
*/
#ifndef __UBOOT__
#include <linux/device.h>
#include <linux/kernel.h>
#endif
#include <linux/mtd/spinand.h>
/* ESMT uses GigaDevice 0xc8 JECDEC ID on some SPI NANDs */
#define SPINAND_MFR_ESMT_C8 0xc8
static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
static SPINAND_OP_VARIANTS(write_cache_variants,
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
SPINAND_PROG_LOAD(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(false, 0, NULL, 0));
/*
* OOB spare area map (64 bytes)
*
* Bad Block Markers
* filled by HW and kernel Reserved
* | +-----------------------+-----------------------+
* | | | |
* | | OOB free data Area |non ECC protected |
* | +-------------|-----+-----------------|-----+-----------------|-----+
* | | | | | | | |
* +-|---|----------+--|-----|--------------+--|-----|--------------+--|-----|--------------+
* | | | section0 | | | section1 | | | section2 | | | section3 |
* +-v-+-v-+---+----+--v--+--v--+-----+-----+--v--+--v--+-----+-----+--v--+--v--+-----+-----+
* | | | | | | | | | | | | | | | | |
* |0:1|2:3|4:7|8:15|16:17|18:19|20:23|24:31|32:33|34:35|36:39|40:47|48:49|50:51|52:55|56:63|
* | | | | | | | | | | | | | | | | |
* +---+---+-^-+--^-+-----+-----+--^--+--^--+-----+-----+--^--+--^--+-----+-----+--^--+--^--+
* | | | | | | | |
* | +----------------|-----+-----------------|-----+-----------------|-----+
* | ECC Area|(Main + Spare) - filled|by ESMT NAND HW |
* | | | |
* +---------------------+-----------------------+-----------------------+
* OOB ECC protected Area - not used due to
* partial programming from some filesystems
* (like JFFS2 with cleanmarkers)
*/
#define ESMT_OOB_SECTION_COUNT 4
#define ESMT_OOB_SECTION_SIZE(nand) \
(nanddev_per_page_oobsize(nand) / ESMT_OOB_SECTION_COUNT)
#define ESMT_OOB_FREE_SIZE(nand) \
(ESMT_OOB_SECTION_SIZE(nand) / 2)
#define ESMT_OOB_ECC_SIZE(nand) \
(ESMT_OOB_SECTION_SIZE(nand) - ESMT_OOB_FREE_SIZE(nand))
#define ESMT_OOB_BBM_SIZE 2
static int f50l1g41lb_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
struct nand_device *nand = mtd_to_nanddev(mtd);
if (section >= ESMT_OOB_SECTION_COUNT)
return -ERANGE;
region->offset = section * ESMT_OOB_SECTION_SIZE(nand) +
ESMT_OOB_FREE_SIZE(nand);
region->length = ESMT_OOB_ECC_SIZE(nand);
return 0;
}
static int f50l1g41lb_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
struct nand_device *nand = mtd_to_nanddev(mtd);
if (section >= ESMT_OOB_SECTION_COUNT)
return -ERANGE;
/*
* Reserve space for bad blocks markers (section0) and
* reserved bytes (sections 1-3)
*/
region->offset = section * ESMT_OOB_SECTION_SIZE(nand) + 2;
/* Use only 2 non-protected ECC bytes per each OOB section */
region->length = 2;
return 0;
}
static const struct mtd_ooblayout_ops f50l1g41lb_ooblayout = {
.ecc = f50l1g41lb_ooblayout_ecc,
.rfree = f50l1g41lb_ooblayout_free,
};
static const struct spinand_info esmt_c8_spinand_table[] = {
SPINAND_INFO("F50L1G41LB",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
SPINAND_INFO("F50D1G41LB",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
};
static const struct spinand_manufacturer_ops esmt_spinand_manuf_ops = {
};
const struct spinand_manufacturer esmt_c8_spinand_manufacturer = {
.id = SPINAND_MFR_ESMT_C8,
.name = "ESMT",
.chips = esmt_c8_spinand_table,
.nchips = ARRAY_SIZE(esmt_c8_spinand_table),
.ops = &esmt_spinand_manuf_ops,
};

View file

@ -176,6 +176,11 @@ config SPI_FLASH_MACRONIX
help
Add support for various Macronix SPI flash chips (MX25Lxxx)
config SPI_FLASH_SILICONKAISER
bool "Silicon Kaiser SPI flash support"
help
Add support for various Silicon Kaiser SPI flash chips (SK25Lxxx)
config SPI_FLASH_SPANSION
bool "Spansion SPI flash support"
help

View file

@ -2089,6 +2089,36 @@ read_err:
return ret;
}
/**
* spi_nor_read_sfdp_dma_unsafe() - read Serial Flash Discoverable Parameters.
* @nor: pointer to a 'struct spi_nor'
* @addr: offset in the SFDP area to start reading data from
* @len: number of bytes to read
* @buf: buffer where the SFDP data are copied into
*
* Wrap spi_nor_read_sfdp() using a kmalloc'ed bounce buffer as @buf is now not
* guaranteed to be dma-safe.
*
* Return: -ENOMEM if kmalloc() fails, the return code of spi_nor_read_sfdp()
* otherwise.
*/
static int spi_nor_read_sfdp_dma_unsafe(struct spi_nor *nor, u32 addr,
size_t len, void *buf)
{
void *dma_safe_buf;
int ret;
dma_safe_buf = kmalloc(len, GFP_KERNEL);
if (!dma_safe_buf)
return -ENOMEM;
ret = spi_nor_read_sfdp(nor, addr, len, dma_safe_buf);
memcpy(buf, dma_safe_buf, len);
kfree(dma_safe_buf);
return ret;
}
/* Fast Read settings. */
static void
@ -2262,7 +2292,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
bfpt_header->length * sizeof(u32));
addr = SFDP_PARAM_HEADER_PTP(bfpt_header);
memset(&bfpt, 0, sizeof(bfpt));
err = spi_nor_read_sfdp(nor, addr, len, &bfpt);
err = spi_nor_read_sfdp_dma_unsafe(nor, addr, len, &bfpt);
if (err < 0)
return err;
@ -2588,7 +2618,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
int i, err;
/* Get the SFDP header. */
err = spi_nor_read_sfdp(nor, 0, sizeof(header), &header);
err = spi_nor_read_sfdp_dma_unsafe(nor, 0, sizeof(header), &header);
if (err < 0)
return err;

View file

@ -200,6 +200,11 @@ const struct flash_info spi_nor_ids[] = {
SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)},
{INFO("gd55lx02g", 0xc8681C, 0, 64 * 1024, 4096, SECT_4K |
SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES)},
{
INFO("gd55lb02ge", 0xc8671c, 0, 64 * 1024, 4096,
SECT_4K | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
#endif
#ifdef CONFIG_SPI_FLASH_ISSI /* ISSI */
/* ISSI */
@ -287,6 +292,10 @@ const struct flash_info spi_nor_ids[] = {
{ INFO("mx25uw6345g", 0xc28437, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
#endif
#ifdef CONFIG_SPI_FLASH_SILICONKAISER
{ INFO("sk25lp128", 0x257018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
#endif
#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */
/* Micron */
{ INFO("n25q016a", 0x20bb15, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_QUAD_READ) },
@ -300,6 +309,7 @@ const struct flash_info spi_nor_ids[] = {
{ INFO("n25q256a", 0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_FSR) },
{ INFO6("mt25qu256a", 0x20bb19, 0x104400, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_FSR) },
{ INFO("n25q256ax1", 0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ | USE_FSR) },
{ INFO("mt25qu128ab", 0x20bb18, 0, 64 * 1024, 256, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
{ INFO6("mt25qu512a", 0x20bb20, 0x104400, 64 * 1024, 1024,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES |
USE_FSR) },
@ -309,6 +319,7 @@ const struct flash_info spi_nor_ids[] = {
{ 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("mt25ql01g", 0x21ba20, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
{ INFO6("mt25qu01g", 0x20bb21, 0x104400, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE | SPI_NOR_4B_OPCODES) },
{ INFO("mt25qu02g", 0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
{ INFO("mt25ql02g", 0x20ba22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE | SPI_NOR_4B_OPCODES) },
#ifdef CONFIG_SPI_FLASH_MT35XU
@ -513,6 +524,16 @@ const struct flash_info spi_nor_ids[] = {
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{
INFO("w25q01jvfim", 0xef7021, 0, 64 * 1024, 2048,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{
INFO("w25q02jv", 0xef7022, 0, 64 * 1024, 4096,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{ INFO("w25q80", 0xef5014, 0, 64 * 1024, 16, SECT_4K) },
{ INFO("w25q80bl", 0xef4014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("w25q16cl", 0xef4015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
@ -566,6 +587,8 @@ const struct flash_info spi_nor_ids[] = {
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ INFO("xt25q01g", 0x0b601B, 0, 64 * 1024, 2048,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ INFO("xt55q02g", 0x0b601C, 0, 64 * 1024, 4096,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
/* adding these wide voltage QSPI flash parts */
{ INFO("xt25w512", 0x0b651A, 0, 64 * 1024, 1024,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },

View file

@ -295,7 +295,7 @@ static int bcm63xx_hsspi_xfer_dummy_cs(struct udevice *dev, unsigned int data_by
/* transfer loop */
while (data_bytes > 0) {
size_t curr_step = min(step_size, data_bytes);
size_t curr_step = min(step_size, (size_t)data_bytes);
int ret;
/* copy tx data */

View file

@ -39,6 +39,11 @@ __weak int cadence_qspi_versal_flash_reset(struct udevice *dev)
return 0;
}
__weak ofnode cadence_qspi_get_subnode(struct udevice *dev)
{
return dev_read_first_subnode(dev);
}
static int cadence_spi_write_speed(struct udevice *bus, uint hz)
{
struct cadence_spi_priv *priv = dev_get_priv(bus);
@ -400,7 +405,7 @@ static int cadence_spi_of_to_plat(struct udevice *bus)
plat->is_dma = dev_read_bool(bus, "cdns,is-dma");
/* All other parameters are embedded in the child node */
subnode = dev_read_first_subnode(bus);
subnode = cadence_qspi_get_subnode(bus);
if (!ofnode_valid(subnode)) {
printf("Error: subnode with SPI flash config missing!\n");
return -ENODEV;

View file

@ -304,6 +304,7 @@ int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_priv *priv);
int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg);
int cadence_qspi_versal_flash_reset(struct udevice *dev);
ofnode cadence_qspi_get_subnode(struct udevice *dev);
void cadence_qspi_apb_enable_linear_mode(bool enable);
#endif /* __CADENCE_QSPI_H__ */

View file

@ -171,8 +171,7 @@ static unsigned int cadence_qspi_wait_idle(void *reg_base)
}
/* Timeout, still in busy mode. */
printf("QSPI: QSPI is still busy after poll for %d times.\n",
CQSPI_REG_RETRY);
printf("QSPI: QSPI is still busy after poll for %d ms.\n", timeout);
return 0;
}

View file

@ -250,6 +250,7 @@ extern const struct spinand_manufacturer micron_spinand_manufacturer;
extern const struct spinand_manufacturer paragon_spinand_manufacturer;
extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
extern const struct spinand_manufacturer winbond_spinand_manufacturer;
extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
/**
* struct spinand_op_variants - SPI NAND operation variants