Merge tag 'u-boot-nand-20240414' of https://source.denx.de/u-boot/custodians/u-boot-nand-flash
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:
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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,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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user