mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-27 01:11:14 +00:00
b9d58f7e06
generic: Add/rename patches for upstream consistency ipq40xx: generic-level patch replaces same-source patches-4.19/ 082-v4.20-mtd-spinand-winbond-Add-support-for-W25N01GV.patch The SPI-NAND framework from Linux uses common driver code that is then "tuned" by a tiny struct of chip-specific data that describes available commands, timing, and layout (data and OOB data). Several manufacturers and chips have been added since 4.19, several of which are used in devices already supported by OpenWrt (typically with no or "legacy" access to their NAND memory). This commit catches up the supported-chip definitions through Linux 5.2-rc6 and linux/next. The driver is only compiled for platforms with CONFIG_MTD_SPI_NAND=y. This presently includes ipq40xx and pistachio, with the addition of ath79-nand in these commits (and not ath79-generic or ath79-tiny). Upstream patches refreshed against 4.19.75 Build-tested-on: ipq40xx Run-tested-on: ath79-nand Signed-off-by: Jeff Kletsky <git-commits@allycomm.com>
130 lines
3.6 KiB
Diff
130 lines
3.6 KiB
Diff
From c40c7a990a46e5102a1cc4190557bf315d32d80d Mon Sep 17 00:00:00 2001
|
|
From: Stefan Roese <sr@denx.de>
|
|
Date: Thu, 24 Jan 2019 13:48:06 +0100
|
|
Subject: [PATCH 8/8] mtd: spinand: Add support for GigaDevice GD5F1GQ4UExxG
|
|
|
|
Add support for GigaDevice GD5F1GQ4UExxG SPI NAND chip.
|
|
|
|
Signed-off-by: Stefan Roese <sr@denx.de>
|
|
Cc: Chuanhong Guo <gch981213@gmail.com>
|
|
Cc: Frieder Schrempf <frieder.schrempf@kontron.de>
|
|
Cc: Miquel Raynal <miquel.raynal@bootlin.com>
|
|
Cc: Boris Brezillon <bbrezillon@kernel.org>
|
|
Reviewed-by: Boris Brezillon <bbrezillon@kernel.org>
|
|
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
|
---
|
|
drivers/mtd/nand/spi/gigadevice.c | 83 +++++++++++++++++++++++++++++++
|
|
1 file changed, 83 insertions(+)
|
|
|
|
--- a/drivers/mtd/nand/spi/gigadevice.c
|
|
+++ b/drivers/mtd/nand/spi/gigadevice.c
|
|
@@ -12,6 +12,8 @@
|
|
#define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4)
|
|
#define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4)
|
|
|
|
+#define GD5FXGQ4UEXXG_REG_STATUS2 0xf0
|
|
+
|
|
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),
|
|
@@ -81,11 +83,83 @@ static int gd5fxgq4xa_ecc_get_status(str
|
|
return -EINVAL;
|
|
}
|
|
|
|
+static int gd5fxgq4uexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
|
|
+ struct mtd_oob_region *region)
|
|
+{
|
|
+ if (section)
|
|
+ return -ERANGE;
|
|
+
|
|
+ region->offset = 64;
|
|
+ region->length = 64;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int gd5fxgq4uexxg_ooblayout_free(struct mtd_info *mtd, int section,
|
|
+ struct mtd_oob_region *region)
|
|
+{
|
|
+ if (section)
|
|
+ return -ERANGE;
|
|
+
|
|
+ /* Reserve 1 bytes for the BBM. */
|
|
+ region->offset = 1;
|
|
+ region->length = 63;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
|
|
+ u8 status)
|
|
+{
|
|
+ u8 status2;
|
|
+ struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQ4UEXXG_REG_STATUS2,
|
|
+ &status2);
|
|
+ int ret;
|
|
+
|
|
+ switch (status & STATUS_ECC_MASK) {
|
|
+ case STATUS_ECC_NO_BITFLIPS:
|
|
+ return 0;
|
|
+
|
|
+ case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
|
|
+ /*
|
|
+ * Read status2 register to determine a more fine grained
|
|
+ * bit error status
|
|
+ */
|
|
+ ret = spi_mem_exec_op(spinand->spimem, &op);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ /*
|
|
+ * 4 ... 7 bits are flipped (1..4 can't be detected, so
|
|
+ * report the maximum of 4 in this case
|
|
+ */
|
|
+ /* bits sorted this way (3...0): ECCS1,ECCS0,ECCSE1,ECCSE0 */
|
|
+ return ((status & STATUS_ECC_MASK) >> 2) |
|
|
+ ((status2 & STATUS_ECC_MASK) >> 4);
|
|
+
|
|
+ case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
|
|
+ return 8;
|
|
+
|
|
+ case STATUS_ECC_UNCOR_ERROR:
|
|
+ return -EBADMSG;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
|
|
.ecc = gd5fxgq4xa_ooblayout_ecc,
|
|
.free = gd5fxgq4xa_ooblayout_free,
|
|
};
|
|
|
|
+static const struct mtd_ooblayout_ops gd5fxgq4uexxg_ooblayout = {
|
|
+ .ecc = gd5fxgq4uexxg_ooblayout_ecc,
|
|
+ .free = gd5fxgq4uexxg_ooblayout_free,
|
|
+};
|
|
+
|
|
static const struct spinand_info gigadevice_spinand_table[] = {
|
|
SPINAND_INFO("GD5F1GQ4xA", 0xF1,
|
|
NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
|
|
@@ -114,6 +188,15 @@ static const struct spinand_info gigadev
|
|
0,
|
|
SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
|
|
gd5fxgq4xa_ecc_get_status)),
|
|
+ SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
|
|
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
|
|
+ NAND_ECCREQ(8, 512),
|
|
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
|
+ &write_cache_variants,
|
|
+ &update_cache_variants),
|
|
+ 0,
|
|
+ SPINAND_ECCINFO(&gd5fxgq4uexxg_ooblayout,
|
|
+ gd5fxgq4uexxg_ecc_get_status)),
|
|
};
|
|
|
|
static int gigadevice_spinand_detect(struct spinand_device *spinand)
|