The first patch is by Weizhao Ouyang and avoids sf probe crashes.

The second patch is by Arseniy Krasnov and adds basic support for Amlogic
Meson NAND controller on AXG.

The following four patches are by Alexander Dahl and apply some fixes to
drivers/mtd/nand/raw/ and port some changes applied in Linux.

The following patch is by Bruce Suen and adds support for XTX SPINAND.

Finally, the last patch is again by Arseniy Krasnov and adds access to
OTP region, supporting info, dump, write and lock operations.
This commit is contained in:
Tom Rini
2024-04-14 15:55:14 -06:00
13 changed files with 1834 additions and 62 deletions
+7
View File
@@ -1361,6 +1361,13 @@ config CMD_MTD
help
MTD commands support.
config CMD_MTD_OTP
bool "mtd otp"
depends on CMD_MTD
select HEXDUMP
help
MTD commands for OTP access.
config CMD_MUX
bool "mux"
depends on MULTIPLEXER
+234
View File
@@ -11,6 +11,9 @@
#include <command.h>
#include <common.h>
#include <console.h>
#if CONFIG_IS_ENABLED(CMD_MTD_OTP)
#include <hexdump.h>
#endif
#include <malloc.h>
#include <mapmem.h>
#include <mtd.h>
@@ -202,6 +205,221 @@ static bool mtd_oob_write_is_empty(struct mtd_oob_ops *op)
return true;
}
#if CONFIG_IS_ENABLED(CMD_MTD_OTP)
static int do_mtd_otp_read(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
struct mtd_info *mtd;
size_t retlen;
off_t from;
size_t len;
bool user;
int ret;
u8 *buf;
if (argc != 5)
return CMD_RET_USAGE;
if (!strcmp(argv[2], "u"))
user = true;
else if (!strcmp(argv[2], "f"))
user = false;
else
return CMD_RET_USAGE;
mtd = get_mtd_by_name(argv[1]);
if (IS_ERR_OR_NULL(mtd))
return CMD_RET_FAILURE;
from = simple_strtoul(argv[3], NULL, 0);
len = simple_strtoul(argv[4], NULL, 0);
ret = CMD_RET_FAILURE;
buf = malloc(len);
if (!buf)
goto put_mtd;
printf("Reading %s OTP from 0x%lx, %zu bytes\n",
user ? "user" : "factory", from, len);
if (user)
ret = mtd_read_user_prot_reg(mtd, from, len, &retlen, buf);
else
ret = mtd_read_fact_prot_reg(mtd, from, len, &retlen, buf);
if (ret) {
free(buf);
pr_err("OTP read failed: %d\n", ret);
ret = CMD_RET_FAILURE;
goto put_mtd;
}
if (retlen != len)
pr_err("OTP read returns %zu, but %zu expected\n",
retlen, len);
print_hex_dump("", 0, 16, 1, buf, retlen, true);
free(buf);
ret = CMD_RET_SUCCESS;
put_mtd:
put_mtd_device(mtd);
return ret;
}
static int do_mtd_otp_lock(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
struct mtd_info *mtd;
off_t from;
size_t len;
int ret;
if (argc != 4)
return CMD_RET_USAGE;
mtd = get_mtd_by_name(argv[1]);
if (IS_ERR_OR_NULL(mtd))
return CMD_RET_FAILURE;
from = simple_strtoul(argv[2], NULL, 0);
len = simple_strtoul(argv[3], NULL, 0);
ret = mtd_lock_user_prot_reg(mtd, from, len);
if (ret) {
pr_err("OTP lock failed: %d\n", ret);
ret = CMD_RET_FAILURE;
goto put_mtd;
}
ret = CMD_RET_SUCCESS;
put_mtd:
put_mtd_device(mtd);
return ret;
}
static int do_mtd_otp_write(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
struct mtd_info *mtd;
size_t retlen;
size_t binlen;
u8 *binbuf;
off_t from;
int ret;
if (argc != 4)
return CMD_RET_USAGE;
mtd = get_mtd_by_name(argv[1]);
if (IS_ERR_OR_NULL(mtd))
return CMD_RET_FAILURE;
from = simple_strtoul(argv[2], NULL, 0);
binlen = strlen(argv[3]) / 2;
ret = CMD_RET_FAILURE;
binbuf = malloc(binlen);
if (!binbuf)
goto put_mtd;
hex2bin(binbuf, argv[3], binlen);
printf("Will write:\n");
print_hex_dump("", 0, 16, 1, binbuf, binlen, true);
printf("to 0x%lx\n", from);
printf("Continue (y/n)?\n");
if (confirm_yesno() != 1) {
pr_err("OTP write canceled\n");
ret = CMD_RET_SUCCESS;
goto put_mtd;
}
ret = mtd_write_user_prot_reg(mtd, from, binlen, &retlen, binbuf);
if (ret) {
pr_err("OTP write failed: %d\n", ret);
ret = CMD_RET_FAILURE;
goto put_mtd;
}
if (retlen != binlen)
pr_err("OTP write returns %zu, but %zu expected\n",
retlen, binlen);
ret = CMD_RET_SUCCESS;
put_mtd:
free(binbuf);
put_mtd_device(mtd);
return ret;
}
static int do_mtd_otp_info(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
struct otp_info otp_info;
struct mtd_info *mtd;
size_t retlen;
bool user;
int ret;
if (argc != 3)
return CMD_RET_USAGE;
if (!strcmp(argv[2], "u"))
user = true;
else if (!strcmp(argv[2], "f"))
user = false;
else
return CMD_RET_USAGE;
mtd = get_mtd_by_name(argv[1]);
if (IS_ERR_OR_NULL(mtd))
return CMD_RET_FAILURE;
if (user)
ret = mtd_get_user_prot_info(mtd, sizeof(otp_info), &retlen,
&otp_info);
else
ret = mtd_get_fact_prot_info(mtd, sizeof(otp_info), &retlen,
&otp_info);
if (ret) {
pr_err("OTP info failed: %d\n", ret);
ret = CMD_RET_FAILURE;
goto put_mtd;
}
if (retlen != sizeof(otp_info)) {
pr_err("OTP info returns %zu, but %zu expected\n",
retlen, sizeof(otp_info));
ret = CMD_RET_FAILURE;
goto put_mtd;
}
printf("%s OTP region info:\n", user ? "User" : "Factory");
printf("\tstart: %u\n", otp_info.start);
printf("\tlength: %u\n", otp_info.length);
printf("\tlocked: %u\n", otp_info.locked);
ret = CMD_RET_SUCCESS;
put_mtd:
put_mtd_device(mtd);
return ret;
}
#endif
static int do_mtd_list(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
@@ -551,6 +769,12 @@ U_BOOT_LONGHELP(mtd,
"\n"
"Specific functions:\n"
"mtd bad <name>\n"
#if CONFIG_IS_ENABLED(CMD_MTD_OTP)
"mtd otpread <name> [u|f] <off> <size>\n"
"mtd otpwrite <name> <off> <hex string>\n"
"mtd otplock <name> <off> <size>\n"
"mtd otpinfo <name> [u|f]\n"
#endif
"\n"
"With:\n"
"\t<name>: NAND partition/chip name (or corresponding DM device name or OF path)\n"
@@ -561,10 +785,20 @@ U_BOOT_LONGHELP(mtd,
"\t<size>: length of the operation in bytes (default: the entire device)\n"
"\t\t* must be a multiple of a block for erase\n"
"\t\t* must be a multiple of a page otherwise (special case: default is a page with dump)\n"
#if CONFIG_IS_ENABLED(CMD_MTD_OTP)
"\t<hex string>: hex string without '0x' and spaces. Example: ABCD1234\n"
"\t[u|f]: user or factory OTP region\n"
#endif
"\n"
"The .dontskipff option forces writing empty pages, don't use it if unsure.\n");
U_BOOT_CMD_WITH_SUBCMDS(mtd, "MTD utils", mtd_help_text,
#if CONFIG_IS_ENABLED(CMD_MTD_OTP)
U_BOOT_SUBCMD_MKENT(otpread, 5, 1, do_mtd_otp_read),
U_BOOT_SUBCMD_MKENT(otpwrite, 4, 1, do_mtd_otp_write),
U_BOOT_SUBCMD_MKENT(otplock, 4, 1, do_mtd_otp_lock),
U_BOOT_SUBCMD_MKENT(otpinfo, 3, 1, do_mtd_otp_info),
#endif
U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mtd_list),
U_BOOT_SUBCMD_MKENT_COMPLETE(read, 5, 0, do_mtd_io,
mtd_name_complete),
+3 -2
View File
@@ -135,8 +135,9 @@ static int do_spi_flash_probe(int argc, char *const argv[])
}
flash = NULL;
if (use_dt) {
spi_flash_probe_bus_cs(bus, cs, &new);
flash = dev_get_uclass_priv(new);
ret = spi_flash_probe_bus_cs(bus, cs, &new);
if (!ret)
flash = dev_get_uclass_priv(new);
} else {
flash = spi_flash_probe(bus, cs, speed, mode);
}
+62 -53
View File
@@ -1,6 +1,6 @@
menuconfig MTD_RAW_NAND
bool "Raw NAND Device Support"
if MTD_RAW_NAND
config SYS_NAND_SELF_INIT
@@ -49,12 +49,12 @@ config SYS_NAND_NO_SUBPAGE_WRITE
depends on NAND_ARASAN || NAND_DAVINCI || NAND_KIRKWOOD
config DM_NAND_ATMEL
bool "Support Atmel NAND controller with DM support"
select SYS_NAND_SELF_INIT
imply SYS_NAND_USE_FLASH_BBT
help
Enable this driver for NAND flash platforms using an Atmel NAND
controller.
bool "Support Atmel NAND controller with DM support"
select SYS_NAND_SELF_INIT
imply SYS_NAND_USE_FLASH_BBT
help
Enable this driver for NAND flash platforms using an Atmel NAND
controller.
config NAND_ATMEL
bool "Support Atmel NAND controller"
@@ -133,35 +133,35 @@ config NAND_BRCMNAND_6753
Enable support for broadcom nand driver on bcm6753.
config NAND_BRCMNAND_68360
bool "Support Broadcom NAND controller on bcm68360"
depends on NAND_BRCMNAND && BCM6856
help
Enable support for broadcom nand driver on bcm68360.
bool "Support Broadcom NAND controller on bcm68360"
depends on NAND_BRCMNAND && BCM6856
help
Enable support for broadcom nand driver on bcm68360.
config NAND_BRCMNAND_6838
bool "Support Broadcom NAND controller on bcm6838"
depends on NAND_BRCMNAND && ARCH_BMIPS && SOC_BMIPS_BCM6838
help
Enable support for broadcom nand driver on bcm6838.
bool "Support Broadcom NAND controller on bcm6838"
depends on NAND_BRCMNAND && ARCH_BMIPS && SOC_BMIPS_BCM6838
help
Enable support for broadcom nand driver on bcm6838.
config NAND_BRCMNAND_6858
bool "Support Broadcom NAND controller on bcm6858"
depends on NAND_BRCMNAND && BCM6858
help
Enable support for broadcom nand driver on bcm6858.
bool "Support Broadcom NAND controller on bcm6858"
depends on NAND_BRCMNAND && BCM6858
help
Enable support for broadcom nand driver on bcm6858.
config NAND_BRCMNAND_63158
bool "Support Broadcom NAND controller on bcm63158"
depends on NAND_BRCMNAND && BCM63158
help
Enable support for broadcom nand driver on bcm63158.
bool "Support Broadcom NAND controller on bcm63158"
depends on NAND_BRCMNAND && BCM63158
help
Enable support for broadcom nand driver on bcm63158.
config NAND_BRCMNAND_IPROC
bool "Support Broadcom NAND controller on the iproc family"
depends on NAND_BRCMNAND
help
Enable support for broadcom nand driver on the Broadcom
iproc family such as Northstar (BCM5301x, BCM4708...)
bool "Support Broadcom NAND controller on the iproc family"
depends on NAND_BRCMNAND
help
Enable support for broadcom nand driver on the Broadcom
iproc family such as Northstar (BCM5301x, BCM4708...)
config NAND_DAVINCI
bool "Support TI Davinci NAND controller"
@@ -413,10 +413,10 @@ config NAND_VF610_NFC
if NAND_VF610_NFC
config NAND_VF610_NFC_DT
bool "Support Vybrid's vf610 NAND controller as a DT device"
depends on OF_CONTROL && DM_MTD
help
Enable the driver for Vybrid's vf610 NAND flash on platforms
bool "Support Vybrid's vf610 NAND controller as a DT device"
depends on OF_CONTROL && DM_MTD
help
Enable the driver for Vybrid's vf610 NAND flash on platforms
using device tree.
choice
@@ -472,11 +472,11 @@ config NAND_SUNXI
select SPL_NAND_SUPPORT
select SPL_SYS_NAND_SELF_INIT
imply CMD_NAND
---help---
Enable support for NAND. This option enables the standard and
SPL drivers.
The SPL driver only supports reading from the NAND using DMA
transfers.
help
Enable support for NAND. This option enables the standard and
SPL drivers.
The SPL driver only supports reading from the NAND using DMA
transfers.
if NAND_SUNXI
@@ -504,6 +504,15 @@ config NAND_ARASAN
controller. This uses the hardware ECC for read and
write operations.
config NAND_MESON
bool "Meson NAND support"
select SYS_NAND_SELF_INIT
depends on DM_MTD && ARCH_MESON
imply CMD_NAND
help
This enables Nand driver support for Meson raw NAND flash
controller.
config NAND_MXC
bool "MXC NAND support"
depends on CPU_ARM926EJS || CPU_ARM1136 || MX5
@@ -577,16 +586,16 @@ config NAND_OCTEONTX
select SYS_NAND_SELF_INIT
imply CMD_NAND
help
This enables Nand flash controller hardware found on the OcteonTX
processors.
This enables Nand flash controller hardware found on the OcteonTX
processors.
config NAND_OCTEONTX_HW_ECC
bool "Support Hardware ECC for OcteonTX NAND controller"
depends on NAND_OCTEONTX
default y
help
This enables Hardware BCH engine found on the OcteonTX processors to
support ECC for NAND flash controller.
This enables Hardware BCH engine found on the OcteonTX processors to
support ECC for NAND flash controller.
config NAND_STM32_FMC2
bool "Support for NAND controller on STM32MP SoCs"
@@ -751,37 +760,37 @@ config SYS_NAND_BAD_BLOCK_POS
config SYS_NAND_U_BOOT_LOCATIONS
bool "Define U-Boot binaries locations in NAND"
help
Enable CONFIG_SYS_NAND_U_BOOT_OFFS though Kconfig.
This option should not be enabled when compiling U-Boot for boards
defining CONFIG_SYS_NAND_U_BOOT_OFFS in their include/configs/<board>.h
file.
Enable CONFIG_SYS_NAND_U_BOOT_OFFS though Kconfig.
This option should not be enabled when compiling U-Boot for boards
defining CONFIG_SYS_NAND_U_BOOT_OFFS in their include/configs/<board>.h
file.
config SYS_NAND_U_BOOT_OFFS
hex "Location in NAND to read U-Boot from"
default 0x800000 if NAND_SUNXI
depends on SYS_NAND_U_BOOT_LOCATIONS
help
Set the offset from the start of the nand where u-boot should be
loaded from.
Set the offset from the start of the nand where u-boot should be
loaded from.
config SYS_NAND_U_BOOT_OFFS_REDUND
hex "Location in NAND to read U-Boot from"
default SYS_NAND_U_BOOT_OFFS
depends on SYS_NAND_U_BOOT_LOCATIONS
help
Set the offset from the start of the nand where the redundant u-boot
should be loaded from.
Set the offset from the start of the nand where the redundant u-boot
should be loaded from.
config SPL_NAND_AM33XX_BCH
bool "Enables SPL-NAND driver which supports ELM based"
depends on SPL_NAND_SUPPORT && NAND_OMAP_GPMC && !OMAP34XX
default y
help
help
Hardware ECC correction. This is useful for platforms which have ELM
hardware engine and use NAND boot mode.
Some legacy platforms like OMAP3xx do not have in-built ELM h/w engine,
so those platforms should use CONFIG_SPL_NAND_SIMPLE for enabling
SPL-NAND driver with software ECC correction support.
SPL-NAND driver with software ECC correction support.
config SPL_NAND_DENALI
bool "Support Denali NAND controller for SPL"
@@ -810,6 +819,6 @@ config SYS_NAND_HW_ECC_OOBFIRST
bool "In SPL, read the OOB first and then the data from NAND"
depends on SPL_NAND_SIMPLE
endif
endif # if SPL
endif # if NAND
endif # if MTD_RAW_NAND
+1
View File
@@ -61,6 +61,7 @@ obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o
obj-$(CONFIG_NAND_LPC32XX_MLC) += lpc32xx_nand_mlc.o
obj-$(CONFIG_NAND_LPC32XX_SLC) += lpc32xx_nand_slc.o
obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o
obj-$(CONFIG_NAND_MESON) += meson_nand.o
obj-$(CONFIG_NAND_MXC) += mxc_nand.o
obj-$(CONFIG_NAND_MXS) += mxs_nand.o
obj-$(CONFIG_NAND_MXS_DT) += mxs_nand_dt.o
+1 -3
View File
@@ -1267,7 +1267,7 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
return ret;
/*
* The write cycle timing is directly matching tWC, but is also
* The read cycle timing is directly matching tRC, but is also
* dependent on the setup and hold timings we calculated earlier,
* which gives:
*
@@ -1429,8 +1429,6 @@ static int atmel_nand_setup_data_interface(struct mtd_info *mtd, int csline,
return nc->caps->ops->setup_data_interface(nand, csline, conf);
}
#define NAND_KEEP_TIMINGS 0x00800000
static void atmel_nand_init(struct atmel_nand_controller *nc,
struct atmel_nand *nand)
{
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -4118,7 +4118,7 @@ static int nand_get_bits_per_cell(u8 cellinfo)
*/
void nand_decode_ext_id(struct nand_chip *chip)
{
struct mtd_info *mtd = &chip->mtd;
struct mtd_info *mtd = nand_to_mtd(chip);
int extid;
/* The 3rd id byte holds MLC / multichip data */
chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]);
@@ -4185,7 +4185,7 @@ static int nand_manufacturer_init(struct nand_chip *chip)
*/
static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type)
{
struct mtd_info *mtd = &chip->mtd;
struct mtd_info *mtd = nand_to_mtd(chip);
mtd->erasesize = type->erasesize;
mtd->writesize = type->pagesize;
@@ -4265,7 +4265,7 @@ static const struct nand_manufacturer *nand_get_manufacturer_desc(u8 id)
int nand_detect(struct nand_chip *chip, int *maf_id,
int *dev_id, struct nand_flash_dev *type)
{
struct mtd_info *mtd = &chip->mtd;
struct mtd_info *mtd = nand_to_mtd(chip);
const struct nand_manufacturer *manufacturer_desc;
int busw, ret;
u8 *id_data = chip->id.data;
+1 -1
View File
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
spinand-objs := core.o esmt.o gigadevice.o macronix.o micron.o paragon.o
spinand-objs += toshiba.o winbond.o
spinand-objs += toshiba.o winbond.o xtx.o
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
+1
View File
@@ -829,6 +829,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
&toshiba_spinand_manufacturer,
&winbond_spinand_manufacturer,
&esmt_c8_spinand_manufacturer,
&xtx_spinand_manufacturer,
};
static int spinand_manufacturer_match(struct spinand_device *spinand,
+266
View File
@@ -0,0 +1,266 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Author:
* Felix Matouschek <felix@matouschek.org>
*/
#include <linux/bitfield.h>
#ifndef __UBOOT__
#include <linux/device.h>
#include <linux/kernel.h>
#endif
#include <linux/mtd/spinand.h>
#define SPINAND_MFR_XTX 0x0B
#define XT26G0XA_STATUS_ECC_MASK GENMASK(5, 2)
#define XT26G0XA_STATUS_ECC_NO_DETECTED (0 << 2)
#define XT26G0XA_STATUS_ECC_8_CORRECTED (3 << 4)
#define XT26G0XA_STATUS_ECC_UNCOR_ERROR (2 << 4)
#define XT26XXXD_STATUS_ECC3_ECC2_MASK GENMASK(7, 6)
#define XT26XXXD_STATUS_ECC_NO_DETECTED (0)
#define XT26XXXD_STATUS_ECC_1_7_CORRECTED (1)
#define XT26XXXD_STATUS_ECC_8_CORRECTED (3)
#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));
static SPINAND_OP_VARIANTS(write_cache_variants,
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
SPINAND_PROG_LOAD(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(false, 0, NULL, 0));
static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
return -ERANGE;
region->offset = 48;
region->length = 16;
return 0;
}
static int xt26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
return -ERANGE;
region->offset = 1;
region->length = 47;
return 0;
}
static const struct mtd_ooblayout_ops xt26g0xa_ooblayout = {
.ecc = xt26g0xa_ooblayout_ecc,
.rfree = xt26g0xa_ooblayout_free,
};
static int xt26g0xa_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
status = status & XT26G0XA_STATUS_ECC_MASK;
switch (status) {
case XT26G0XA_STATUS_ECC_NO_DETECTED:
return 0;
case XT26G0XA_STATUS_ECC_8_CORRECTED:
return 8;
case XT26G0XA_STATUS_ECC_UNCOR_ERROR:
return -EBADMSG;
default:
break;
}
/* At this point values greater than (2 << 4) are invalid */
if (status > XT26G0XA_STATUS_ECC_UNCOR_ERROR)
return -EINVAL;
/* (1 << 2) through (7 << 2) are 1-7 corrected errors */
return status >> 2;
}
static int xt26xxxd_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
return -ERANGE;
region->offset = mtd->oobsize / 2;
region->length = mtd->oobsize / 2;
return 0;
}
static int xt26xxxd_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
return -ERANGE;
region->offset = 2;
region->length = mtd->oobsize / 2 - 2;
return 0;
}
static const struct mtd_ooblayout_ops xt26xxxd_ooblayout = {
.ecc = xt26xxxd_ooblayout_ecc,
.rfree = xt26xxxd_ooblayout_free,
};
static int xt26xxxd_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
switch (FIELD_GET(STATUS_ECC_MASK, status)) {
case XT26XXXD_STATUS_ECC_NO_DETECTED:
return 0;
case XT26XXXD_STATUS_ECC_UNCOR_ERROR:
return -EBADMSG;
case XT26XXXD_STATUS_ECC_1_7_CORRECTED:
return 4 + FIELD_GET(XT26XXXD_STATUS_ECC3_ECC2_MASK, status);
case XT26XXXD_STATUS_ECC_8_CORRECTED:
return 8;
default:
break;
}
return -EINVAL;
}
static const struct spinand_info xtx_spinand_table[] = {
SPINAND_INFO("XT26G01A",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE1),
NAND_MEMORG(1, 2048, 64, 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(&xt26g0xa_ooblayout,
xt26g0xa_ecc_get_status)),
SPINAND_INFO("XT26G02A",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE2),
NAND_MEMORG(1, 2048, 64, 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(&xt26g0xa_ooblayout,
xt26g0xa_ecc_get_status)),
SPINAND_INFO("XT26G04A",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE3),
NAND_MEMORG(1, 2048, 64, 128, 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(&xt26g0xa_ooblayout,
xt26g0xa_ecc_get_status)),
SPINAND_INFO("XT26G01D",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x31),
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),
0,
SPINAND_ECCINFO(&xt26xxxd_ooblayout,
xt26xxxd_ecc_get_status)),
SPINAND_INFO("XT26G11D",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x34),
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),
0,
SPINAND_ECCINFO(&xt26xxxd_ooblayout,
xt26xxxd_ecc_get_status)),
SPINAND_INFO("XT26Q01D",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51),
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),
0,
SPINAND_ECCINFO(&xt26xxxd_ooblayout,
xt26xxxd_ecc_get_status)),
SPINAND_INFO("XT26G02D",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x32),
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),
0,
SPINAND_ECCINFO(&xt26xxxd_ooblayout,
xt26xxxd_ecc_get_status)),
SPINAND_INFO("XT26G12D",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x35),
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),
0,
SPINAND_ECCINFO(&xt26xxxd_ooblayout,
xt26xxxd_ecc_get_status)),
SPINAND_INFO("XT26Q02D",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x52),
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),
0,
SPINAND_ECCINFO(&xt26xxxd_ooblayout,
xt26xxxd_ecc_get_status)),
SPINAND_INFO("XT26G04D",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x33),
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),
0,
SPINAND_ECCINFO(&xt26xxxd_ooblayout,
xt26xxxd_ecc_get_status)),
SPINAND_INFO("XT26Q04D",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x53),
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),
0,
SPINAND_ECCINFO(&xt26xxxd_ooblayout,
xt26xxxd_ecc_get_status)),
};
static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = {
};
const struct spinand_manufacturer xtx_spinand_manufacturer = {
.id = SPINAND_MFR_XTX,
.name = "XTX",
.chips = xtx_spinand_table,
.nchips = ARRAY_SIZE(xtx_spinand_table),
.ops = &xtx_spinand_manuf_ops,
};
+7
View File
@@ -249,6 +249,13 @@ enum nand_ecc_algo {
*/
#define NAND_USE_BOUNCE_BUFFER 0x00100000
/*
* Do not try to tweak the timings at runtime. This is needed when the
* controller initializes the timings on itself or when it relies on
* configuration done by the bootloader.
*/
#define NAND_KEEP_TIMINGS 0x00800000
/* Options set by nand scan */
/* bbt has already been read */
#define NAND_BBT_SCANNED 0x40000000
+1
View File
@@ -251,6 +251,7 @@ extern const struct spinand_manufacturer paragon_spinand_manufacturer;
extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
extern const struct spinand_manufacturer winbond_spinand_manufacturer;
extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
extern const struct spinand_manufacturer xtx_spinand_manufacturer;
/**
* struct spinand_op_variants - SPI NAND operation variants