mtd: spinand: Sync core code and device support with Linux 6.17-rc1
This makes the U-Boot SPI NAND driver almost the same as in Linux 6.17-rc1. The only major differences are: * support of ECC engines. The Linux driver supports different ECC engines while U-Boot uses on-die ECC only. * per operation maximum SPI bus frequency Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu> Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de> Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
This commit is contained in:
committed by
Michael Trimarchi
parent
1e103284a5
commit
2cbdd3e449
@@ -2,5 +2,5 @@
|
||||
|
||||
spinand-objs := core.o otp.o
|
||||
spinand-objs += alliancememory.o ato.o esmt.o foresee.o gigadevice.o macronix.o
|
||||
spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o
|
||||
spinand-objs += micron.o paragon.o skyhigh.o toshiba.o winbond.o xtx.o
|
||||
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
|
||||
|
||||
@@ -19,20 +19,20 @@
|
||||
#define AM_STATUS_ECC_MAX_CORRECTED (3 << 4)
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_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));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(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));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
static int am_get_eccsize(struct mtd_info *mtd)
|
||||
{
|
||||
|
||||
@@ -11,20 +11,23 @@
|
||||
#endif
|
||||
#include <linux/mtd/spinand.h>
|
||||
|
||||
|
||||
#define SPINAND_MFR_ATO 0x9b
|
||||
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X4_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));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(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));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
|
||||
static int ato25d1ga_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
@@ -60,6 +63,7 @@ static const struct mtd_ooblayout_ops ato25d1ga_ooblayout = {
|
||||
.rfree = ato25d1ga_ooblayout_free,
|
||||
};
|
||||
|
||||
|
||||
static const struct spinand_info ato_spinand_table[] = {
|
||||
SPINAND_INFO("ATO25D1GA",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x12),
|
||||
|
||||
+11
-10
@@ -42,9 +42,9 @@ struct spinand_plat {
|
||||
/* SPI NAND index visible in MTD names */
|
||||
static int spi_nand_idx;
|
||||
|
||||
static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
|
||||
int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_OP(reg,
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(reg,
|
||||
spinand->scratchbuf);
|
||||
int ret;
|
||||
|
||||
@@ -58,7 +58,7 @@ static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
|
||||
|
||||
int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_SET_FEATURE_OP(reg,
|
||||
struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(reg,
|
||||
spinand->scratchbuf);
|
||||
|
||||
*spinand->scratchbuf = val;
|
||||
@@ -357,9 +357,9 @@ static void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status)
|
||||
spinand->last_wait_status = status;
|
||||
}
|
||||
|
||||
static int spinand_write_enable_op(struct spinand_device *spinand)
|
||||
int spinand_write_enable_op(struct spinand_device *spinand)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_WR_EN_DIS_OP(true);
|
||||
struct spi_mem_op op = SPINAND_WR_EN_DIS_1S_0_0_OP(true);
|
||||
|
||||
return spi_mem_exec_op(spinand->slave, &op);
|
||||
}
|
||||
@@ -369,7 +369,7 @@ static int spinand_load_page_op(struct spinand_device *spinand,
|
||||
{
|
||||
struct nand_device *nand = spinand_to_nand(spinand);
|
||||
unsigned int row = nanddev_pos_to_row(nand, &req->pos);
|
||||
struct spi_mem_op op = SPINAND_PAGE_READ_OP(row);
|
||||
struct spi_mem_op op = SPINAND_PAGE_READ_1S_1S_0_OP(row);
|
||||
|
||||
return spi_mem_exec_op(spinand->slave, &op);
|
||||
}
|
||||
@@ -516,7 +516,7 @@ static int spinand_program_op(struct spinand_device *spinand,
|
||||
{
|
||||
struct nand_device *nand = spinand_to_nand(spinand);
|
||||
unsigned int row = nanddev_pos_to_row(nand, &req->pos);
|
||||
struct spi_mem_op op = SPINAND_PROG_EXEC_OP(row);
|
||||
struct spi_mem_op op = SPINAND_PROG_EXEC_1S_1S_0_OP(row);
|
||||
|
||||
return spi_mem_exec_op(spinand->slave, &op);
|
||||
}
|
||||
@@ -526,7 +526,7 @@ static int spinand_erase_op(struct spinand_device *spinand,
|
||||
{
|
||||
struct nand_device *nand = spinand_to_nand(spinand);
|
||||
unsigned int row = nanddev_pos_to_row(nand, pos);
|
||||
struct spi_mem_op op = SPINAND_BLK_ERASE_OP(row);
|
||||
struct spi_mem_op op = SPINAND_BLK_ERASE_1S_1S_0_OP(row);
|
||||
|
||||
return spi_mem_exec_op(spinand->slave, &op);
|
||||
}
|
||||
@@ -586,7 +586,7 @@ out:
|
||||
static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr,
|
||||
u8 ndummy, u8 *buf)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_READID_OP(
|
||||
struct spi_mem_op op = SPINAND_READID_1S_1S_1S_OP(
|
||||
naddr, ndummy, spinand->scratchbuf, SPINAND_MAX_ID_LEN);
|
||||
int ret;
|
||||
|
||||
@@ -599,7 +599,7 @@ static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr,
|
||||
|
||||
static int spinand_reset_op(struct spinand_device *spinand)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_RESET_OP;
|
||||
struct spi_mem_op op = SPINAND_RESET_1S_0_0_OP;
|
||||
int ret;
|
||||
|
||||
ret = spi_mem_exec_op(spinand->slave, &op);
|
||||
@@ -1188,6 +1188,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
|
||||
¯onix_spinand_manufacturer,
|
||||
µn_spinand_manufacturer,
|
||||
¶gon_spinand_manufacturer,
|
||||
&skyhigh_spinand_manufacturer,
|
||||
&toshiba_spinand_manufacturer,
|
||||
&winbond_spinand_manufacturer,
|
||||
&xtx_spinand_manufacturer,
|
||||
|
||||
+100
-11
@@ -8,25 +8,33 @@
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#else
|
||||
#include <dm/device_compat.h>
|
||||
#include <spi-mem.h>
|
||||
#include <spi.h>
|
||||
#endif
|
||||
#include <linux/mtd/spinand.h>
|
||||
|
||||
/* ESMT uses GigaDevice 0xc8 JECDEC ID on some SPI NANDs */
|
||||
#define SPINAND_MFR_ESMT_C8 0xc8
|
||||
|
||||
#define ESMT_F50L1G41LB_CFG_OTP_PROTECT BIT(7)
|
||||
#define ESMT_F50L1G41LB_CFG_OTP_LOCK \
|
||||
(CFG_OTP_ENABLE | ESMT_F50L1G41LB_CFG_OTP_PROTECT)
|
||||
|
||||
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));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(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));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
/*
|
||||
* OOB spare area map (64 bytes)
|
||||
@@ -104,6 +112,83 @@ static const struct mtd_ooblayout_ops f50l1g41lb_ooblayout = {
|
||||
.rfree = f50l1g41lb_ooblayout_free,
|
||||
};
|
||||
|
||||
static int f50l1g41lb_otp_info(struct spinand_device *spinand, size_t len,
|
||||
struct otp_info *buf, size_t *retlen, bool user)
|
||||
{
|
||||
if (len < sizeof(*buf))
|
||||
return -EINVAL;
|
||||
|
||||
buf->locked = 0;
|
||||
buf->start = 0;
|
||||
buf->length = user ? spinand_user_otp_size(spinand) :
|
||||
spinand_fact_otp_size(spinand);
|
||||
|
||||
*retlen = sizeof(*buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int f50l1g41lb_fact_otp_info(struct spinand_device *spinand, size_t len,
|
||||
struct otp_info *buf, size_t *retlen)
|
||||
{
|
||||
return f50l1g41lb_otp_info(spinand, len, buf, retlen, false);
|
||||
}
|
||||
|
||||
static int f50l1g41lb_user_otp_info(struct spinand_device *spinand, size_t len,
|
||||
struct otp_info *buf, size_t *retlen)
|
||||
{
|
||||
return f50l1g41lb_otp_info(spinand, len, buf, retlen, true);
|
||||
}
|
||||
|
||||
static int f50l1g41lb_otp_lock(struct spinand_device *spinand, loff_t from,
|
||||
size_t len)
|
||||
{
|
||||
struct spi_mem_op write_op = SPINAND_WR_EN_DIS_1S_0_0_OP(true);
|
||||
struct spi_mem_op exec_op = SPINAND_PROG_EXEC_1S_1S_0_OP(0);
|
||||
u8 status;
|
||||
int ret;
|
||||
|
||||
ret = spinand_upd_cfg(spinand, ESMT_F50L1G41LB_CFG_OTP_LOCK,
|
||||
ESMT_F50L1G41LB_CFG_OTP_LOCK);
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
ret = spi_mem_exec_op(spinand->slave, &write_op);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
ret = spi_mem_exec_op(spinand->slave, &exec_op);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
ret = spinand_wait(spinand,
|
||||
SPINAND_WRITE_INITIAL_DELAY_US,
|
||||
SPINAND_WRITE_POLL_DELAY_US,
|
||||
&status);
|
||||
if (!ret && (status & STATUS_PROG_FAILED))
|
||||
ret = -EIO;
|
||||
|
||||
out:
|
||||
if (spinand_upd_cfg(spinand, ESMT_F50L1G41LB_CFG_OTP_LOCK, 0)) {
|
||||
dev_warn(spinand->slave->dev,
|
||||
"Can not disable OTP mode\n");
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct spinand_user_otp_ops f50l1g41lb_user_otp_ops = {
|
||||
.info = f50l1g41lb_user_otp_info,
|
||||
.lock = f50l1g41lb_otp_lock,
|
||||
.read = spinand_user_otp_read,
|
||||
.write = spinand_user_otp_write,
|
||||
};
|
||||
|
||||
static const struct spinand_fact_otp_ops f50l1g41lb_fact_otp_ops = {
|
||||
.info = f50l1g41lb_fact_otp_info,
|
||||
.read = spinand_fact_otp_read,
|
||||
};
|
||||
|
||||
static const struct spinand_info esmt_c8_spinand_table[] = {
|
||||
SPINAND_INFO("F50L1G41LB",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01, 0x7f,
|
||||
@@ -114,17 +199,21 @@ static const struct spinand_info esmt_c8_spinand_table[] = {
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
|
||||
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL),
|
||||
SPINAND_USER_OTP_INFO(28, 2, &f50l1g41lb_user_otp_ops),
|
||||
SPINAND_FACT_OTP_INFO(2, 0, &f50l1g41lb_fact_otp_ops)),
|
||||
SPINAND_INFO("F50D1G41LB",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11, 0x7f,
|
||||
0x7f, 0x7f),
|
||||
0x7f),
|
||||
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_ECCINFO(&f50l1g41lb_ooblayout, NULL),
|
||||
SPINAND_USER_OTP_INFO(28, 2, &f50l1g41lb_user_otp_ops),
|
||||
SPINAND_FACT_OTP_INFO(2, 0, &f50l1g41lb_fact_otp_ops)),
|
||||
SPINAND_INFO("F50D2G41KA",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51, 0x7f,
|
||||
0x7f, 0x7f),
|
||||
|
||||
@@ -14,18 +14,18 @@
|
||||
#define SPINAND_MFR_FORESEE 0xCD
|
||||
|
||||
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));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(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));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
static int f35sqa002g_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
@@ -83,6 +83,16 @@ static const struct spinand_info foresee_spinand_table[] = {
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&f35sqa002g_ooblayout,
|
||||
f35sqa002g_ecc_get_status)),
|
||||
SPINAND_INFO("F35SQA001G",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71, 0x71),
|
||||
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),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&f35sqa002g_ooblayout,
|
||||
f35sqa002g_ecc_get_status)),
|
||||
};
|
||||
|
||||
static const struct spinand_manufacturer_ops foresee_spinand_manuf_ops = {
|
||||
|
||||
@@ -28,44 +28,44 @@
|
||||
#define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR (7 << 4)
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_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));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants_f,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_3A_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_1S_OP(0, 0, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants_1gq5,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_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));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants_2gq5,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, 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));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(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));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
static int gd5fxgq4xa_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
@@ -189,7 +189,7 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
|
||||
u8 status)
|
||||
{
|
||||
u8 status2;
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(GD5FXGQXXEXXG_REG_STATUS2,
|
||||
spinand->scratchbuf);
|
||||
int ret;
|
||||
|
||||
@@ -232,7 +232,7 @@ static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
|
||||
u8 status)
|
||||
{
|
||||
u8 status2;
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(GD5FXGQXXEXXG_REG_STATUS2,
|
||||
spinand->scratchbuf);
|
||||
int ret;
|
||||
|
||||
@@ -537,6 +537,26 @@ static const struct spinand_info gigadevice_spinand_table[] = {
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
|
||||
gd5fxgq4uexxg_ecc_get_status)),
|
||||
SPINAND_INFO("GD5F1GM9UExxG",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x91, 0x01),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
|
||||
gd5fxgq4uexxg_ecc_get_status)),
|
||||
SPINAND_INFO("GD5F1GM9RExxG",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x81, 0x01),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
|
||||
gd5fxgq4uexxg_ecc_get_status)),
|
||||
};
|
||||
|
||||
static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
|
||||
|
||||
+221
-62
@@ -5,6 +5,7 @@
|
||||
* Author: Boris Brezillon <boris.brezillon@bootlin.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -13,21 +14,35 @@
|
||||
#include <linux/mtd/spinand.h>
|
||||
|
||||
#define SPINAND_MFR_MACRONIX 0xC2
|
||||
#define MACRONIX_ECCSR_MASK 0x0F
|
||||
#define MACRONIX_ECCSR_BF_LAST_PAGE(eccsr) FIELD_GET(GENMASK(3, 0), eccsr)
|
||||
#define MACRONIX_ECCSR_BF_ACCUMULATED_PAGES(eccsr) FIELD_GET(GENMASK(7, 4), eccsr)
|
||||
#define MACRONIX_CFG_CONT_READ BIT(2)
|
||||
#define MACRONIX_FEATURE_ADDR_READ_RETRY 0x70
|
||||
#define MACRONIX_NUM_READ_RETRY_MODES 5
|
||||
|
||||
#define STATUS_ECC_HAS_BITFLIPS_THRESHOLD (3 << 4)
|
||||
|
||||
/* Bitflip theshold configuration register */
|
||||
#define REG_CFG_BFT 0x10
|
||||
#define CFG_BFT(x) FIELD_PREP(GENMASK(7, 4), (x))
|
||||
|
||||
struct macronix_priv {
|
||||
bool cont_read;
|
||||
};
|
||||
|
||||
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));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(false, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 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));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
static int mx35lfxge4ab_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
@@ -52,8 +67,9 @@ static const struct mtd_ooblayout_ops mx35lfxge4ab_ooblayout = {
|
||||
.rfree = mx35lfxge4ab_ooblayout_free,
|
||||
};
|
||||
|
||||
static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
|
||||
static int macronix_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
|
||||
{
|
||||
struct macronix_priv *priv = spinand->priv;
|
||||
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x7c, 1),
|
||||
SPI_MEM_OP_NO_ADDR,
|
||||
SPI_MEM_OP_DUMMY(1, 1),
|
||||
@@ -63,12 +79,21 @@ static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*eccsr &= MACRONIX_ECCSR_MASK;
|
||||
/*
|
||||
* ECCSR exposes the number of bitflips for the last read page in bits [3:0].
|
||||
* Continuous read compatible chips also expose the maximum number of
|
||||
* bitflips for the whole (continuous) read operation in bits [7:4].
|
||||
*/
|
||||
if (!priv->cont_read)
|
||||
*eccsr = MACRONIX_ECCSR_BF_LAST_PAGE(*eccsr);
|
||||
else
|
||||
*eccsr = MACRONIX_ECCSR_BF_ACCUMULATED_PAGES(*eccsr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
|
||||
u8 status)
|
||||
static int macronix_ecc_get_status(struct spinand_device *spinand,
|
||||
u8 status)
|
||||
{
|
||||
struct nand_device *nand = spinand_to_nand(spinand);
|
||||
u8 eccsr;
|
||||
@@ -86,16 +111,14 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
|
||||
* in order to avoid forcing the wear-leveling layer to move
|
||||
* data around if it's not necessary.
|
||||
*/
|
||||
if (mx35lf1ge4ab_get_eccsr(spinand, spinand->scratchbuf))
|
||||
if (macronix_get_eccsr(spinand, spinand->scratchbuf))
|
||||
return nanddev_get_ecc_conf(nand)->strength;
|
||||
|
||||
eccsr = *spinand->scratchbuf;
|
||||
if (WARN_ON(eccsr > nanddev_get_ecc_conf(nand)->strength ||
|
||||
!eccsr))
|
||||
if (WARN_ON(eccsr > nanddev_get_ecc_conf(nand)->strength || !eccsr))
|
||||
return nanddev_get_ecc_conf(nand)->strength;
|
||||
|
||||
return eccsr;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -103,6 +126,38 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int macronix_set_cont_read(struct spinand_device *spinand, bool enable)
|
||||
{
|
||||
struct macronix_priv *priv = spinand->priv;
|
||||
int ret;
|
||||
|
||||
ret = spinand_upd_cfg(spinand, MACRONIX_CFG_CONT_READ,
|
||||
enable ? MACRONIX_CFG_CONT_READ : 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->cont_read = enable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* macronix_set_read_retry - Set the retry mode
|
||||
* @spinand: SPI NAND device
|
||||
* @retry_mode: Specify which retry mode to set
|
||||
*
|
||||
* Return: 0 on success, a negative error code otherwise.
|
||||
*/
|
||||
static int macronix_set_read_retry(struct spinand_device *spinand,
|
||||
unsigned int retry_mode)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(MACRONIX_FEATURE_ADDR_READ_RETRY,
|
||||
spinand->scratchbuf);
|
||||
|
||||
*spinand->scratchbuf = retry_mode;
|
||||
return spi_mem_exec_op(spinand->slave, &op);
|
||||
}
|
||||
|
||||
static const struct spinand_info macronix_spinand_table[] = {
|
||||
SPINAND_INFO("MX35LF1GE4AB",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x12),
|
||||
@@ -113,7 +168,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
macronix_ecc_get_status)),
|
||||
SPINAND_INFO("MX35LF2GE4AB",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
|
||||
@@ -121,10 +176,12 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_HAS_QE_BIT |
|
||||
SPINAND_HAS_PROG_PLANE_SELECT_BIT |
|
||||
SPINAND_HAS_READ_PLANE_SELECT_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
|
||||
SPINAND_INFO("MX35LF2GE4AD",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x26),
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x26, 0x03),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
@@ -132,9 +189,12 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_CONT_READ(macronix_set_cont_read),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
macronix_set_read_retry)),
|
||||
SPINAND_INFO("MX35LF4GE4AD",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37),
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37, 0x03),
|
||||
NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
@@ -142,34 +202,67 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_CONT_READ(macronix_set_cont_read),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
macronix_set_read_retry)),
|
||||
SPINAND_INFO("MX35LF1G24AD",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14, 0x03),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
macronix_set_read_retry)),
|
||||
SPINAND_INFO("MX35LF2G24AD",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24, 0x03),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
|
||||
SPINAND_INFO("MX35LF4G24AD",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
|
||||
NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
|
||||
SPINAND_HAS_QE_BIT |
|
||||
SPINAND_HAS_PROG_PLANE_SELECT_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
macronix_set_read_retry)),
|
||||
SPINAND_INFO("MX35LF2G24AD-Z4I8",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x64, 0x03),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
macronix_set_read_retry)),
|
||||
SPINAND_INFO("MX35LF4G24AD",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35, 0x03),
|
||||
NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT |
|
||||
SPINAND_HAS_PROG_PLANE_SELECT_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
macronix_set_read_retry)),
|
||||
SPINAND_INFO("MX35LF4G24AD-Z4I8",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x75, 0x03),
|
||||
NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
macronix_set_read_retry)),
|
||||
SPINAND_INFO("MX31LF1GE4BC",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||
@@ -179,7 +272,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
macronix_ecc_get_status)),
|
||||
SPINAND_INFO("MX31UF1GE4BC",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9e),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||
@@ -189,7 +282,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
macronix_ecc_get_status)),
|
||||
|
||||
SPINAND_INFO("MX35LF2G14AC",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x20),
|
||||
@@ -198,21 +291,26 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_HAS_QE_BIT |
|
||||
SPINAND_HAS_PROG_PLANE_SELECT_BIT |
|
||||
SPINAND_HAS_READ_PLANE_SELECT_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
macronix_ecc_get_status)),
|
||||
SPINAND_INFO("MX35UF4G24AD",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5),
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5, 0x03),
|
||||
NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_HAS_QE_BIT |
|
||||
SPINAND_HAS_PROG_PLANE_SELECT_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
SPINAND_INFO("MX35UF4GE4AD",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7),
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
macronix_set_read_retry)),
|
||||
SPINAND_INFO("MX35UF4G24AD-Z4I8",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xf5, 0x03),
|
||||
NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
@@ -220,7 +318,22 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
macronix_set_read_retry)),
|
||||
SPINAND_INFO("MX35UF4GE4AD",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7, 0x03),
|
||||
NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_CONT_READ(macronix_set_cont_read),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
macronix_set_read_retry)),
|
||||
SPINAND_INFO("MX35UF2G14AC",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa0),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
|
||||
@@ -228,21 +341,26 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_HAS_QE_BIT |
|
||||
SPINAND_HAS_PROG_PLANE_SELECT_BIT |
|
||||
SPINAND_HAS_READ_PLANE_SELECT_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
macronix_ecc_get_status)),
|
||||
SPINAND_INFO("MX35UF2G24AD",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4),
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4, 0x03),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_HAS_QE_BIT |
|
||||
SPINAND_HAS_PROG_PLANE_SELECT_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
SPINAND_INFO("MX35UF2GE4AD",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6),
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
macronix_set_read_retry)),
|
||||
SPINAND_INFO("MX35UF2G24AD-Z4I8",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe4, 0x03),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
@@ -250,9 +368,24 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
macronix_set_read_retry)),
|
||||
SPINAND_INFO("MX35UF2GE4AD",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6, 0x03),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_CONT_READ(macronix_set_cont_read),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
macronix_set_read_retry)),
|
||||
SPINAND_INFO("MX35UF2GE4AC",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2),
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2, 0x01),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
|
||||
NAND_ECCREQ(4, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
@@ -260,7 +393,8 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_CONT_READ(macronix_set_cont_read)),
|
||||
SPINAND_INFO("MX35UF1G14AC",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x90),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||
@@ -270,9 +404,9 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
macronix_ecc_get_status)),
|
||||
SPINAND_INFO("MX35UF1G24AD",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94),
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94, 0x03),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
@@ -280,9 +414,11 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
macronix_set_read_retry)),
|
||||
SPINAND_INFO("MX35UF1GE4AD",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96),
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96, 0x03),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
@@ -290,9 +426,12 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_CONT_READ(macronix_set_cont_read),
|
||||
SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES,
|
||||
macronix_set_read_retry)),
|
||||
SPINAND_INFO("MX35UF1GE4AC",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92),
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92, 0x01),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(4, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
@@ -300,8 +439,8 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
|
||||
macronix_ecc_get_status),
|
||||
SPINAND_CONT_READ(macronix_set_cont_read)),
|
||||
SPINAND_INFO("MX31LF2GE4BC",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x2e),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
|
||||
@@ -311,7 +450,7 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
macronix_ecc_get_status)),
|
||||
SPINAND_INFO("MX3UF2GE4BC",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
|
||||
@@ -321,10 +460,30 @@ static const struct spinand_info macronix_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
SPINAND_HAS_QE_BIT,
|
||||
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
|
||||
mx35lf1ge4ab_ecc_get_status)),
|
||||
macronix_ecc_get_status)),
|
||||
};
|
||||
|
||||
static int macronix_spinand_init(struct spinand_device *spinand)
|
||||
{
|
||||
struct macronix_priv *priv;
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
spinand->priv = priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void macronix_spinand_cleanup(struct spinand_device *spinand)
|
||||
{
|
||||
kfree(spinand->priv);
|
||||
}
|
||||
|
||||
static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
|
||||
.init = macronix_spinand_init,
|
||||
.cleanup = macronix_spinand_cleanup,
|
||||
};
|
||||
|
||||
const struct spinand_manufacturer macronix_spinand_manufacturer = {
|
||||
|
||||
+160
-18
@@ -9,8 +9,14 @@
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spi/spi-mem.h>
|
||||
#else
|
||||
#include <dm/device_compat.h>
|
||||
#include <spi-mem.h>
|
||||
#include <spi.h>
|
||||
#endif
|
||||
#include <linux/mtd/spinand.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#define SPINAND_MFR_MICRON 0x2c
|
||||
|
||||
@@ -30,34 +36,38 @@
|
||||
|
||||
#define MICRON_SELECT_DIE(x) ((x) << 6)
|
||||
|
||||
#define MICRON_MT29F2G01ABAGD_CFG_OTP_STATE BIT(7)
|
||||
#define MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK \
|
||||
(CFG_OTP_ENABLE | MICRON_MT29F2G01ABAGD_CFG_OTP_STATE)
|
||||
|
||||
static SPINAND_OP_VARIANTS(quadio_read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_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));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(x4_write_cache_variants,
|
||||
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(x4_update_cache_variants,
|
||||
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(false, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
/* Micron MT29F2G01AAAED Device */
|
||||
static SPINAND_OP_VARIANTS(x4_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));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(x1_write_cache_variants,
|
||||
SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(x1_update_cache_variants,
|
||||
SPINAND_PROG_LOAD(false, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
@@ -133,7 +143,7 @@ static const struct mtd_ooblayout_ops micron_4_ooblayout = {
|
||||
static int micron_select_target(struct spinand_device *spinand,
|
||||
unsigned int target)
|
||||
{
|
||||
struct spi_mem_op op = SPINAND_SET_FEATURE_OP(MICRON_DIE_SELECT_REG,
|
||||
struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(MICRON_DIE_SELECT_REG,
|
||||
spinand->scratchbuf);
|
||||
|
||||
if (target > 1)
|
||||
@@ -170,6 +180,136 @@ static int micron_8_ecc_get_status(struct spinand_device *spinand,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline bool mem_is_zero(const void *s, size_t n)
|
||||
{
|
||||
return !memchr_inv(s, 0, n);
|
||||
}
|
||||
|
||||
static int mt29f2g01abagd_otp_is_locked(struct spinand_device *spinand)
|
||||
{
|
||||
size_t bufsize = spinand_otp_page_size(spinand);
|
||||
size_t retlen;
|
||||
u8 *buf;
|
||||
int ret;
|
||||
|
||||
buf = kmalloc(bufsize, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = spinand_upd_cfg(spinand,
|
||||
MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK,
|
||||
MICRON_MT29F2G01ABAGD_CFG_OTP_STATE);
|
||||
if (ret)
|
||||
goto free_buf;
|
||||
|
||||
ret = spinand_user_otp_read(spinand, 0, bufsize, &retlen, buf);
|
||||
|
||||
if (spinand_upd_cfg(spinand, MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK,
|
||||
0)) {
|
||||
dev_warn(spinand->slave->dev,
|
||||
"Can not disable OTP mode\n");
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto free_buf;
|
||||
|
||||
/* If all zeros, then the OTP area is locked. */
|
||||
if (mem_is_zero(buf, bufsize))
|
||||
ret = 1;
|
||||
|
||||
free_buf:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt29f2g01abagd_otp_info(struct spinand_device *spinand, size_t len,
|
||||
struct otp_info *buf, size_t *retlen,
|
||||
bool user)
|
||||
{
|
||||
int locked;
|
||||
|
||||
if (len < sizeof(*buf))
|
||||
return -EINVAL;
|
||||
|
||||
locked = mt29f2g01abagd_otp_is_locked(spinand);
|
||||
if (locked < 0)
|
||||
return locked;
|
||||
|
||||
buf->locked = locked;
|
||||
buf->start = 0;
|
||||
buf->length = user ? spinand_user_otp_size(spinand) :
|
||||
spinand_fact_otp_size(spinand);
|
||||
|
||||
*retlen = sizeof(*buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt29f2g01abagd_fact_otp_info(struct spinand_device *spinand,
|
||||
size_t len, struct otp_info *buf,
|
||||
size_t *retlen)
|
||||
{
|
||||
return mt29f2g01abagd_otp_info(spinand, len, buf, retlen, false);
|
||||
}
|
||||
|
||||
static int mt29f2g01abagd_user_otp_info(struct spinand_device *spinand,
|
||||
size_t len, struct otp_info *buf,
|
||||
size_t *retlen)
|
||||
{
|
||||
return mt29f2g01abagd_otp_info(spinand, len, buf, retlen, true);
|
||||
}
|
||||
|
||||
static int mt29f2g01abagd_otp_lock(struct spinand_device *spinand, loff_t from,
|
||||
size_t len)
|
||||
{
|
||||
struct spi_mem_op write_op = SPINAND_WR_EN_DIS_1S_0_0_OP(true);
|
||||
struct spi_mem_op exec_op = SPINAND_PROG_EXEC_1S_1S_0_OP(0);
|
||||
u8 status;
|
||||
int ret;
|
||||
|
||||
ret = spinand_upd_cfg(spinand,
|
||||
MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK,
|
||||
MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK);
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
ret = spi_mem_exec_op(spinand->slave, &write_op);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
ret = spi_mem_exec_op(spinand->slave, &exec_op);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
ret = spinand_wait(spinand,
|
||||
SPINAND_WRITE_INITIAL_DELAY_US,
|
||||
SPINAND_WRITE_POLL_DELAY_US,
|
||||
&status);
|
||||
if (!ret && (status & STATUS_PROG_FAILED))
|
||||
ret = -EIO;
|
||||
|
||||
out:
|
||||
if (spinand_upd_cfg(spinand, MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK, 0)) {
|
||||
dev_warn(spinand->slave->dev,
|
||||
"Can not disable OTP mode\n");
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct spinand_user_otp_ops mt29f2g01abagd_user_otp_ops = {
|
||||
.info = mt29f2g01abagd_user_otp_info,
|
||||
.lock = mt29f2g01abagd_otp_lock,
|
||||
.read = spinand_user_otp_read,
|
||||
.write = spinand_user_otp_write,
|
||||
};
|
||||
|
||||
static const struct spinand_fact_otp_ops mt29f2g01abagd_fact_otp_ops = {
|
||||
.info = mt29f2g01abagd_fact_otp_info,
|
||||
.read = spinand_fact_otp_read,
|
||||
};
|
||||
|
||||
static const struct spinand_info micron_spinand_table[] = {
|
||||
/* M79A 2Gb 3.3V */
|
||||
SPINAND_INFO("MT29F2G01ABAGD",
|
||||
@@ -181,7 +321,9 @@ static const struct spinand_info micron_spinand_table[] = {
|
||||
&x4_update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(µn_8_ooblayout,
|
||||
micron_8_ecc_get_status)),
|
||||
micron_8_ecc_get_status),
|
||||
SPINAND_USER_OTP_INFO(12, 2, &mt29f2g01abagd_user_otp_ops),
|
||||
SPINAND_FACT_OTP_INFO(2, 0, &mt29f2g01abagd_fact_otp_ops)),
|
||||
/* M79A 2Gb 1.8V */
|
||||
SPINAND_INFO("MT29F2G01ABBGD",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
#endif
|
||||
#include <linux/mtd/spinand.h>
|
||||
|
||||
|
||||
#define SPINAND_MFR_PARAGON 0xa1
|
||||
|
||||
|
||||
#define PN26G0XA_STATUS_ECC_BITMASK (3 << 4)
|
||||
|
||||
#define PN26G0XA_STATUS_ECC_NONE_DETECTED (0 << 4)
|
||||
@@ -20,21 +22,23 @@
|
||||
#define PN26G0XA_STATUS_ECC_ERRORED (2 << 4)
|
||||
#define PN26G0XA_STATUS_ECC_8_CORRECTED (3 << 4)
|
||||
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_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));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(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));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
|
||||
static int pn26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2024 SkyHigh Memory Limited
|
||||
*
|
||||
* Author: Takahiro Kuwano <takahiro.kuwano@infineon.com>
|
||||
* Co-Author: KR Kim <kr.kim@skyhighmemory.com>
|
||||
*/
|
||||
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#endif
|
||||
#include <linux/mtd/spinand.h>
|
||||
|
||||
#define SPINAND_MFR_SKYHIGH 0x01
|
||||
#define SKYHIGH_STATUS_ECC_1TO2_BITFLIPS (1 << 4)
|
||||
#define SKYHIGH_STATUS_ECC_3TO6_BITFLIPS (2 << 4)
|
||||
#define SKYHIGH_STATUS_ECC_UNCOR_ERROR (3 << 4)
|
||||
#define SKYHIGH_CONFIG_PROTECT_EN BIT(1)
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(update_cache_variants,
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
static int skyhigh_spinand_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
/* ECC bytes are stored in hidden area. */
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
static int skyhigh_spinand_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
if (section)
|
||||
return -ERANGE;
|
||||
|
||||
/* ECC bytes are stored in hidden area. Reserve 2 bytes for the BBM. */
|
||||
region->offset = 2;
|
||||
region->length = mtd->oobsize - 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mtd_ooblayout_ops skyhigh_spinand_ooblayout = {
|
||||
.ecc = skyhigh_spinand_ooblayout_ecc,
|
||||
.rfree = skyhigh_spinand_ooblayout_free,
|
||||
};
|
||||
|
||||
static int skyhigh_spinand_ecc_get_status(struct spinand_device *spinand,
|
||||
u8 status)
|
||||
{
|
||||
switch (status & STATUS_ECC_MASK) {
|
||||
case STATUS_ECC_NO_BITFLIPS:
|
||||
return 0;
|
||||
|
||||
case SKYHIGH_STATUS_ECC_UNCOR_ERROR:
|
||||
return -EBADMSG;
|
||||
|
||||
case SKYHIGH_STATUS_ECC_1TO2_BITFLIPS:
|
||||
return 2;
|
||||
|
||||
case SKYHIGH_STATUS_ECC_3TO6_BITFLIPS:
|
||||
return 6;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct spinand_info skyhigh_spinand_table[] = {
|
||||
SPINAND_INFO("S35ML01G301",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(6, 32),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_NO_RAW_ACCESS,
|
||||
SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
|
||||
skyhigh_spinand_ecc_get_status)),
|
||||
SPINAND_INFO("S35ML01G300",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(6, 32),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_NO_RAW_ACCESS,
|
||||
SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
|
||||
skyhigh_spinand_ecc_get_status)),
|
||||
SPINAND_INFO("S35ML02G300",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
|
||||
NAND_ECCREQ(6, 32),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_NO_RAW_ACCESS,
|
||||
SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
|
||||
skyhigh_spinand_ecc_get_status)),
|
||||
SPINAND_INFO("S35ML04G300",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 2, 1, 1),
|
||||
NAND_ECCREQ(6, 32),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
SPINAND_NO_RAW_ACCESS,
|
||||
SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
|
||||
skyhigh_spinand_ecc_get_status)),
|
||||
};
|
||||
|
||||
static int skyhigh_spinand_init(struct spinand_device *spinand)
|
||||
{
|
||||
/*
|
||||
* Config_Protect_En (bit 1 in Block Lock register) must be set to 1
|
||||
* before writing other bits. Do it here before core unlocks all blocks
|
||||
* by writing block protection bits.
|
||||
*/
|
||||
return spinand_write_reg_op(spinand, REG_BLOCK_LOCK,
|
||||
SKYHIGH_CONFIG_PROTECT_EN);
|
||||
}
|
||||
|
||||
static const struct spinand_manufacturer_ops skyhigh_spinand_manuf_ops = {
|
||||
.init = skyhigh_spinand_init,
|
||||
};
|
||||
|
||||
const struct spinand_manufacturer skyhigh_spinand_manufacturer = {
|
||||
.id = SPINAND_MFR_SKYHIGH,
|
||||
.name = "SkyHigh",
|
||||
.chips = skyhigh_spinand_table,
|
||||
.nchips = ARRAY_SIZE(skyhigh_spinand_table),
|
||||
.ops = &skyhigh_spinand_manuf_ops,
|
||||
};
|
||||
@@ -18,28 +18,28 @@
|
||||
#define TOSH_STATUS_ECC_HAS_BITFLIPS_T (3 << 4)
|
||||
|
||||
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));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_x4_variants,
|
||||
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(update_cache_x4_variants,
|
||||
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(false, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
/*
|
||||
* Backward compatibility for 1st generation Serial NAND devices
|
||||
* which don't support Quad Program Load operation.
|
||||
*/
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(update_cache_variants,
|
||||
SPINAND_PROG_LOAD(false, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
static int tx58cxgxsxraix_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
@@ -76,7 +76,7 @@ static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
|
||||
{
|
||||
struct nand_device *nand = spinand_to_nand(spinand);
|
||||
u8 mbf = 0;
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, spinand->scratchbuf);
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(0x30, spinand->scratchbuf);
|
||||
|
||||
switch (status & STATUS_ECC_MASK) {
|
||||
case STATUS_ECC_NO_BITFLIPS:
|
||||
|
||||
+323
-55
@@ -14,28 +14,83 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/mtd/spinand.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define HZ_PER_MHZ 1000000UL
|
||||
|
||||
#define SPINAND_MFR_WINBOND 0xEF
|
||||
|
||||
#define WINBOND_CFG_BUF_READ BIT(3)
|
||||
|
||||
#define W25N04KV_STATUS_ECC_5_8_BITFLIPS FIELD_PREP_CONST(STATUS_ECC_MASK, 0x3)
|
||||
#define W25N04KV_STATUS_ECC_5_8_BITFLIPS (3 << 4)
|
||||
|
||||
#define W25N0XJW_SR4 0xD0
|
||||
#define W25N0XJW_SR4_HS BIT(2)
|
||||
|
||||
#define W35N01JW_VCR_IO_MODE 0x00
|
||||
#define W35N01JW_VCR_IO_MODE_SINGLE_SDR 0xFF
|
||||
#define W35N01JW_VCR_IO_MODE_OCTAL_SDR 0xDF
|
||||
#define W35N01JW_VCR_IO_MODE_OCTAL_DDR_DS 0xE7
|
||||
#define W35N01JW_VCR_IO_MODE_OCTAL_DDR 0xC7
|
||||
#define W35N01JW_VCR_DUMMY_CLOCK_REG 0x01
|
||||
|
||||
/*
|
||||
* "X2" in the core is equivalent to "dual output" in the datasheets,
|
||||
* "X4" in the core is equivalent to "quad output" in the datasheets.
|
||||
* Quad and octal capable chips feature an absolute maximum frequency of 166MHz.
|
||||
*/
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_octal_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(0, 3, NULL, 0, 120 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(0, 2, NULL, 0, 105 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 20, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 16, NULL, 0, 162 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 12, NULL, 0, 124 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 8, NULL, 0, 86 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_8S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_8S_OP(0, 1, NULL, 0, 133 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_octal_variants,
|
||||
SPINAND_PROG_LOAD_1S_8S_8S_OP(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_8S_OP(0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(update_cache_octal_variants,
|
||||
SPINAND_PROG_LOAD_1S_8S_8S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_dual_quad_dtr_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4D_4D_OP(0, 8, NULL, 0, 80 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1D_4D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 104 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2D_2D_OP(0, 4, NULL, 0, 80 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1D_2D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 104 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1D_1D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 54 * HZ_PER_MHZ));
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_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));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(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));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
@@ -80,6 +135,18 @@ static int w25m02gv_select_target(struct spinand_device *spinand,
|
||||
return spi_mem_exec_op(spinand->slave, &op);
|
||||
}
|
||||
|
||||
static int w25n01kv_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
if (section > 3)
|
||||
return -ERANGE;
|
||||
|
||||
region->offset = 64 + (8 * section);
|
||||
region->length = 7;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
@@ -104,17 +171,57 @@ static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mtd_ooblayout_ops w25n01kv_ooblayout = {
|
||||
.ecc = w25n01kv_ooblayout_ecc,
|
||||
.rfree = w25n02kv_ooblayout_free,
|
||||
};
|
||||
|
||||
static const struct mtd_ooblayout_ops w25n02kv_ooblayout = {
|
||||
.ecc = w25n02kv_ooblayout_ecc,
|
||||
.rfree = w25n02kv_ooblayout_free,
|
||||
};
|
||||
|
||||
static int w35n01jw_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
if (section > 7)
|
||||
return -ERANGE;
|
||||
|
||||
region->offset = (16 * section) + 12;
|
||||
region->length = 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int w35n01jw_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
if (section > 7)
|
||||
return -ERANGE;
|
||||
|
||||
region->offset = 16 * section;
|
||||
region->length = 12;
|
||||
|
||||
/* Extract BBM */
|
||||
if (!section) {
|
||||
region->offset += 2;
|
||||
region->length -= 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mtd_ooblayout_ops w35n01jw_ooblayout = {
|
||||
.ecc = w35n01jw_ooblayout_ecc,
|
||||
.rfree = w35n01jw_ooblayout_free,
|
||||
};
|
||||
|
||||
static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
|
||||
u8 status)
|
||||
{
|
||||
struct nand_device *nand = spinand_to_nand(spinand);
|
||||
u8 mbf = 0;
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, spinand->scratchbuf);
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(0x30, spinand->scratchbuf);
|
||||
|
||||
switch (status & STATUS_ECC_MASK) {
|
||||
case STATUS_ECC_NO_BITFLIPS:
|
||||
@@ -147,8 +254,194 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int w25n0xjw_hs_cfg(struct spinand_device *spinand)
|
||||
{
|
||||
const struct spi_mem_op *op;
|
||||
bool hs;
|
||||
u8 sr4;
|
||||
int ret;
|
||||
|
||||
op = spinand->op_templates.read_cache;
|
||||
if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
|
||||
hs = false;
|
||||
else if (op->cmd.buswidth == 1 && op->addr.buswidth == 1 &&
|
||||
op->dummy.buswidth == 1 && op->data.buswidth == 1)
|
||||
hs = false;
|
||||
else if (!op->max_freq)
|
||||
hs = true;
|
||||
else
|
||||
hs = false;
|
||||
|
||||
ret = spinand_read_reg_op(spinand, W25N0XJW_SR4, &sr4);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (hs)
|
||||
sr4 |= W25N0XJW_SR4_HS;
|
||||
else
|
||||
sr4 &= ~W25N0XJW_SR4_HS;
|
||||
|
||||
ret = spinand_write_reg_op(spinand, W25N0XJW_SR4, sr4);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int w35n0xjw_write_vcr(struct spinand_device *spinand, u8 reg, u8 val)
|
||||
{
|
||||
struct spi_mem_op op =
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x81, 1),
|
||||
SPI_MEM_OP_ADDR(3, reg, 1),
|
||||
SPI_MEM_OP_NO_DUMMY,
|
||||
SPI_MEM_OP_DATA_OUT(1, spinand->scratchbuf, 1));
|
||||
int ret;
|
||||
|
||||
*spinand->scratchbuf = val;
|
||||
|
||||
ret = spinand_write_enable_op(spinand);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = spi_mem_exec_op(spinand->slave, &op);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Write VCR operation doesn't set the busy bit in SR, which means we
|
||||
* cannot perform a status poll. Minimum time of 50ns is needed to
|
||||
* complete the write.
|
||||
*/
|
||||
ndelay(50);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int w35n0xjw_vcr_cfg(struct spinand_device *spinand)
|
||||
{
|
||||
const struct spi_mem_op *op;
|
||||
unsigned int dummy_cycles;
|
||||
bool dtr, single;
|
||||
u8 io_mode;
|
||||
int ret;
|
||||
|
||||
op = spinand->op_templates.read_cache;
|
||||
|
||||
single = (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && op->data.buswidth == 1);
|
||||
dtr = (op->cmd.dtr || op->addr.dtr || op->data.dtr);
|
||||
if (single && !dtr)
|
||||
io_mode = W35N01JW_VCR_IO_MODE_SINGLE_SDR;
|
||||
else if (!single && !dtr)
|
||||
io_mode = W35N01JW_VCR_IO_MODE_OCTAL_SDR;
|
||||
else if (!single && dtr)
|
||||
io_mode = W35N01JW_VCR_IO_MODE_OCTAL_DDR;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_IO_MODE, io_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dummy_cycles = ((op->dummy.nbytes * 8) / op->dummy.buswidth) / (op->dummy.dtr ? 2 : 1);
|
||||
switch (dummy_cycles) {
|
||||
case 8:
|
||||
case 12:
|
||||
case 16:
|
||||
case 20:
|
||||
case 24:
|
||||
case 28:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_DUMMY_CLOCK_REG, dummy_cycles);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spinand_info winbond_spinand_table[] = {
|
||||
SPINAND_INFO("W25M02GV",
|
||||
/* 512M-bit densities */
|
||||
SPINAND_INFO("W25N512GW", /* 1.8V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x20),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 512, 10, 1, 1, 1),
|
||||
NAND_ECCREQ(1, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
|
||||
/* 1G-bit densities */
|
||||
SPINAND_INFO("W25N01GV", /* 3.3V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21),
|
||||
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(&w25m02gv_ooblayout, NULL)),
|
||||
SPINAND_INFO("W25N01GW", /* 1.8V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x21),
|
||||
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(&w25m02gv_ooblayout, NULL)),
|
||||
SPINAND_INFO("W25N01JW", /* high-speed 1.8V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbc, 0x21),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(1, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_dual_quad_dtr_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
|
||||
SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)),
|
||||
SPINAND_INFO("W25N01KV", /* 3.3V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21),
|
||||
NAND_MEMORG(1, 2048, 96, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(4, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w25n01kv_ooblayout, w25n02kv_ecc_get_status)),
|
||||
SPINAND_INFO("W35N01JW", /* 1.8V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc, 0x21),
|
||||
NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 1, 1),
|
||||
NAND_ECCREQ(1, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants,
|
||||
&write_cache_octal_variants,
|
||||
&update_cache_octal_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
|
||||
SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
|
||||
SPINAND_INFO("W35N02JW", /* 1.8V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x22),
|
||||
NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 2, 1),
|
||||
NAND_ECCREQ(1, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants,
|
||||
&write_cache_octal_variants,
|
||||
&update_cache_octal_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
|
||||
SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
|
||||
SPINAND_INFO("W35N04JW", /* 1.8V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x23),
|
||||
NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 4, 1),
|
||||
NAND_ECCREQ(1, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants,
|
||||
&write_cache_octal_variants,
|
||||
&update_cache_octal_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
|
||||
SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
|
||||
/* 2G-bit densities */
|
||||
SPINAND_INFO("W25M02GV", /* 2x1G-bit 3.3V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
|
||||
NAND_ECCREQ(1, 512),
|
||||
@@ -158,16 +451,17 @@ static const struct spinand_info winbond_spinand_table[] = {
|
||||
0,
|
||||
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
|
||||
SPINAND_SELECT_TARGET(w25m02gv_select_target)),
|
||||
SPINAND_INFO("W25N01GV",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||
SPINAND_INFO("W25N02JW", /* high-speed 1.8V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbf, 0x22),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 2, 1),
|
||||
NAND_ECCREQ(1, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_dual_quad_dtr_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
|
||||
SPINAND_INFO("W25N02KV",
|
||||
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
|
||||
SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)),
|
||||
SPINAND_INFO("W25N02KV", /* 3.3V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
@@ -176,34 +470,7 @@ static const struct spinand_info winbond_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
|
||||
SPINAND_INFO("W25N01JW",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbc, 0x21),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(4, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w25m02gv_ooblayout, w25n02kv_ecc_get_status)),
|
||||
SPINAND_INFO("W25N02JWZEIF",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbf, 0x22),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 2, 1),
|
||||
NAND_ECCREQ(4, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
|
||||
SPINAND_INFO("W25N512GW",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x20),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 512, 10, 1, 1, 1),
|
||||
NAND_ECCREQ(4, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
|
||||
SPINAND_INFO("W25N02KWZEIR",
|
||||
SPINAND_INFO("W25N02KW", /* 1.8V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x22),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
@@ -212,18 +479,19 @@ static const struct spinand_info winbond_spinand_table[] = {
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
|
||||
SPINAND_INFO("W25N01GWZEIG",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x21),
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||
NAND_ECCREQ(4, 512),
|
||||
/* 4G-bit densities */
|
||||
SPINAND_INFO("W25N04KV", /* 3.3V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 2, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
SPINAND_ECCINFO(&w25m02gv_ooblayout, w25n02kv_ecc_get_status)),
|
||||
SPINAND_INFO("W25N04KV",
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 2, 1, 1),
|
||||
SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
|
||||
SPINAND_INFO("W25N04KW", /* 1.8V */
|
||||
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x23),
|
||||
NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
|
||||
+10
-10
@@ -25,20 +25,20 @@
|
||||
#define XT26XXXD_STATUS_ECC_UNCOR_ERROR (2)
|
||||
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_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));
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
|
||||
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(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));
|
||||
SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
|
||||
|
||||
static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* @oobsize: OOB area size
|
||||
* @pages_per_eraseblock: number of pages per eraseblock
|
||||
* @eraseblocks_per_lun: number of eraseblocks per LUN (Logical Unit Number)
|
||||
* @max_bad_eraseblocks_per_lun: maximum number of eraseblocks per LUN
|
||||
* @max_bad_eraseblocks_per_lun: maximum number of bad eraseblocks per LUN
|
||||
* @planes_per_lun: number of planes per LUN
|
||||
* @luns_per_target: number of LUN per target (target is a synonym for die)
|
||||
* @ntargets: total number of targets exposed by the NAND device
|
||||
@@ -286,6 +286,20 @@ nanddev_pages_per_eraseblock(const struct nand_device *nand)
|
||||
return nand->memorg.pages_per_eraseblock;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_pages_per_target() - Get the number of pages per target
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: the number of pages per target.
|
||||
*/
|
||||
static inline unsigned int
|
||||
nanddev_pages_per_target(const struct nand_device *nand)
|
||||
{
|
||||
return nand->memorg.pages_per_eraseblock *
|
||||
nand->memorg.eraseblocks_per_lun *
|
||||
nand->memorg.luns_per_target;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_per_page_oobsize() - Get NAND erase block size
|
||||
* @nand: NAND device
|
||||
@@ -309,6 +323,18 @@ nanddev_eraseblocks_per_lun(const struct nand_device *nand)
|
||||
return nand->memorg.eraseblocks_per_lun;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_eraseblocks_per_target() - Get the number of eraseblocks per target
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: the number of eraseblocks per target.
|
||||
*/
|
||||
static inline unsigned int
|
||||
nanddev_eraseblocks_per_target(const struct nand_device *nand)
|
||||
{
|
||||
return nand->memorg.eraseblocks_per_lun * nand->memorg.luns_per_target;
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_target_size() - Get the total size provided by a single target/die
|
||||
* @nand: NAND device
|
||||
@@ -335,7 +361,7 @@ static inline unsigned int nanddev_ntargets(const struct nand_device *nand)
|
||||
}
|
||||
|
||||
/**
|
||||
* nanddev_neraseblocks() - Get the total number of erasablocks
|
||||
* nanddev_neraseblocks() - Get the total number of eraseblocks
|
||||
* @nand: NAND device
|
||||
*
|
||||
* Return: the total number of eraseblocks exposed by @nand.
|
||||
|
||||
+136
-41
@@ -26,126 +26,218 @@
|
||||
* Standard SPI NAND flash operations
|
||||
*/
|
||||
|
||||
#define SPINAND_RESET_OP \
|
||||
#define SPINAND_RESET_1S_0_0_OP \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xff, 1), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_WR_EN_DIS_OP(enable) \
|
||||
#define SPINAND_WR_EN_DIS_1S_0_0_OP(enable) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD((enable) ? 0x06 : 0x04, 1), \
|
||||
SPI_MEM_OP_NO_ADDR, \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_READID_OP(naddr, ndummy, buf, len) \
|
||||
#define SPINAND_READID_1S_1S_1S_OP(naddr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1), \
|
||||
SPI_MEM_OP_ADDR(naddr, 0, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1))
|
||||
|
||||
#define SPINAND_SET_FEATURE_OP(reg, valptr) \
|
||||
#define SPINAND_SET_FEATURE_1S_1S_1S_OP(reg, valptr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x1f, 1), \
|
||||
SPI_MEM_OP_ADDR(1, reg, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_OUT(1, valptr, 1))
|
||||
|
||||
#define SPINAND_GET_FEATURE_OP(reg, valptr) \
|
||||
#define SPINAND_GET_FEATURE_1S_1S_1S_OP(reg, valptr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x0f, 1), \
|
||||
SPI_MEM_OP_ADDR(1, reg, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_IN(1, valptr, 1))
|
||||
|
||||
#define SPINAND_BLK_ERASE_OP(addr) \
|
||||
#define SPINAND_BLK_ERASE_1S_1S_0_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xd8, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PAGE_READ_OP(addr) \
|
||||
#define SPINAND_PAGE_READ_1S_1S_0_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x13, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_OP(fast, addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1), \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x03, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_OP_3A(fast, addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1), \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x0b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x03, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP(addr, ndummy, buf, len) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_FAST_3A_1S_1S_1S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x0b, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_1D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x0d, 1), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 1), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(addr, ndummy, buf, len) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_2S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP(addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4))
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_2D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x3d, 1), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(addr, ndummy, buf, len) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 2), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 2), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP_3A(addr, ndummy, buf, len) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_2S_2S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 2), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 2), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(addr, ndummy, buf, len) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_2D_2D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xbd, 1), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 2), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 2), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 2), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_4S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_4D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x6d, 1), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 4), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 4), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 4), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP_3A(addr, ndummy, buf, len) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_3A_1S_4S_4S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 4), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 4), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4))
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PROG_EXEC_OP(addr) \
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_4D_4D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xed, 1), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 4), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 4), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 4), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1S_8S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x8b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 8), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xcb, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 8), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 8), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 8), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(addr, ndummy, buf, len, freq) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x9d, 1), \
|
||||
SPI_MEM_DTR_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_DTR_OP_DATA_IN(len, buf, 8), \
|
||||
SPI_MEM_OP_MAX_FREQ(freq))
|
||||
|
||||
#define SPINAND_PROG_EXEC_1S_1S_0_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_NO_DATA)
|
||||
|
||||
#define SPINAND_PROG_LOAD(reset, addr, buf, len) \
|
||||
#define SPINAND_PROG_LOAD_1S_1S_1S_OP(reset, addr, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x02 : 0x84, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_OUT(len, buf, 1))
|
||||
|
||||
#define SPINAND_PROG_LOAD_X4(reset, addr, buf, len) \
|
||||
#define SPINAND_PROG_LOAD_1S_1S_4S_OP(reset, addr, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x32 : 0x34, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_OUT(len, buf, 4))
|
||||
|
||||
#define SPINAND_PROG_LOAD_1S_1S_8S_OP(addr, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x82, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_OUT(len, buf, 8))
|
||||
|
||||
#define SPINAND_PROG_LOAD_1S_8S_8S_OP(reset, addr, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0xc2 : 0xc4, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 8), \
|
||||
SPI_MEM_OP_NO_DUMMY, \
|
||||
SPI_MEM_OP_DATA_OUT(len, buf, 8))
|
||||
|
||||
/**
|
||||
* Standard SPI NAND flash commands
|
||||
*/
|
||||
@@ -274,6 +366,7 @@ extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer macronix_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer micron_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer paragon_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer skyhigh_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer winbond_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer xtx_spinand_manufacturer;
|
||||
@@ -453,13 +546,13 @@ struct spinand_info {
|
||||
}
|
||||
|
||||
#define SPINAND_SELECT_TARGET(__func) \
|
||||
.select_target = __func,
|
||||
.select_target = __func
|
||||
|
||||
#define SPINAND_CONFIGURE_CHIP(__configure_chip) \
|
||||
.configure_chip = __configure_chip
|
||||
|
||||
#define SPINAND_CONT_READ(__set_cont_read) \
|
||||
.set_cont_read = __set_cont_read,
|
||||
.set_cont_read = __set_cont_read
|
||||
|
||||
#define SPINAND_FACT_OTP_INFO(__npages, __start_page, __ops) \
|
||||
.fact_otp = { \
|
||||
@@ -667,7 +760,9 @@ int spinand_match_and_init(struct spinand_device *spinand,
|
||||
enum spinand_readid_method rdid_method);
|
||||
|
||||
int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
|
||||
int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val);
|
||||
int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val);
|
||||
int spinand_write_enable_op(struct spinand_device *spinand);
|
||||
int spinand_select_target(struct spinand_device *spinand, unsigned int target);
|
||||
|
||||
int spinand_wait(struct spinand_device *spinand, unsigned long initial_delay_us,
|
||||
|
||||
Reference in New Issue
Block a user