mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-25 08:21: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>
189 lines
5.4 KiB
Diff
189 lines
5.4 KiB
Diff
From 10949af1681d5bb5cdbcc012815c6e40eec17d02 Mon Sep 17 00:00:00 2001
|
|
From: Schrempf Frieder <frieder.schrempf@kontron.De>
|
|
Date: Thu, 8 Nov 2018 08:32:11 +0000
|
|
Subject: [PATCH 2/8] mtd: spinand: Add initial support for Toshiba TC58CVG2S0H
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Add minimal support for the Toshiba TC58CVG2S0H SPI NAND chip.
|
|
|
|
Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
|
|
Acked-by: Clément Péron <peron.clem@gmail.com>
|
|
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
|
---
|
|
drivers/mtd/nand/spi/Makefile | 2 +-
|
|
drivers/mtd/nand/spi/core.c | 1 +
|
|
drivers/mtd/nand/spi/toshiba.c | 137 +++++++++++++++++++++++++++++++++
|
|
include/linux/mtd/spinand.h | 1 +
|
|
4 files changed, 140 insertions(+), 1 deletion(-)
|
|
create mode 100644 drivers/mtd/nand/spi/toshiba.c
|
|
|
|
--- a/drivers/mtd/nand/spi/Makefile
|
|
+++ b/drivers/mtd/nand/spi/Makefile
|
|
@@ -1,3 +1,3 @@
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
-spinand-objs := core.o macronix.o micron.o winbond.o
|
|
+spinand-objs := core.o macronix.o micron.o toshiba.o winbond.o
|
|
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
|
|
--- a/drivers/mtd/nand/spi/core.c
|
|
+++ b/drivers/mtd/nand/spi/core.c
|
|
@@ -764,6 +764,7 @@ static const struct nand_ops spinand_ops
|
|
static const struct spinand_manufacturer *spinand_manufacturers[] = {
|
|
¯onix_spinand_manufacturer,
|
|
µn_spinand_manufacturer,
|
|
+ &toshiba_spinand_manufacturer,
|
|
&winbond_spinand_manufacturer,
|
|
};
|
|
|
|
--- /dev/null
|
|
+++ b/drivers/mtd/nand/spi/toshiba.c
|
|
@@ -0,0 +1,137 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright (c) 2018 exceet electronics GmbH
|
|
+ * Copyright (c) 2018 Kontron Electronics GmbH
|
|
+ *
|
|
+ * Author: Frieder Schrempf <frieder.schrempf@kontron.de>
|
|
+ */
|
|
+
|
|
+#include <linux/device.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/mtd/spinand.h>
|
|
+
|
|
+#define SPINAND_MFR_TOSHIBA 0x98
|
|
+#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));
|
|
+
|
|
+static SPINAND_OP_VARIANTS(write_cache_variants,
|
|
+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
|
+
|
|
+static SPINAND_OP_VARIANTS(update_cache_variants,
|
|
+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
|
|
+
|
|
+static int tc58cvg2s0h_ooblayout_ecc(struct mtd_info *mtd, int section,
|
|
+ struct mtd_oob_region *region)
|
|
+{
|
|
+ if (section > 7)
|
|
+ return -ERANGE;
|
|
+
|
|
+ region->offset = 128 + 16 * section;
|
|
+ region->length = 16;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int tc58cvg2s0h_ooblayout_free(struct mtd_info *mtd, int section,
|
|
+ struct mtd_oob_region *region)
|
|
+{
|
|
+ if (section > 0)
|
|
+ return -ERANGE;
|
|
+
|
|
+ /* 2 bytes reserved for BBM */
|
|
+ region->offset = 2;
|
|
+ region->length = 126;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct mtd_ooblayout_ops tc58cvg2s0h_ooblayout = {
|
|
+ .ecc = tc58cvg2s0h_ooblayout_ecc,
|
|
+ .free = tc58cvg2s0h_ooblayout_free,
|
|
+};
|
|
+
|
|
+static int tc58cvg2s0h_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, &mbf);
|
|
+
|
|
+ switch (status & STATUS_ECC_MASK) {
|
|
+ case STATUS_ECC_NO_BITFLIPS:
|
|
+ return 0;
|
|
+
|
|
+ case STATUS_ECC_UNCOR_ERROR:
|
|
+ return -EBADMSG;
|
|
+
|
|
+ case STATUS_ECC_HAS_BITFLIPS:
|
|
+ case TOSH_STATUS_ECC_HAS_BITFLIPS_T:
|
|
+ /*
|
|
+ * Let's try to retrieve the real maximum number of bitflips
|
|
+ * in order to avoid forcing the wear-leveling layer to move
|
|
+ * data around if it's not necessary.
|
|
+ */
|
|
+ if (spi_mem_exec_op(spinand->spimem, &op))
|
|
+ return nand->eccreq.strength;
|
|
+
|
|
+ mbf >>= 4;
|
|
+
|
|
+ if (WARN_ON(mbf > nand->eccreq.strength || !mbf))
|
|
+ return nand->eccreq.strength;
|
|
+
|
|
+ return mbf;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
+static const struct spinand_info toshiba_spinand_table[] = {
|
|
+ SPINAND_INFO("TC58CVG2S0H", 0xCD,
|
|
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 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(&tc58cvg2s0h_ooblayout,
|
|
+ tc58cvg2s0h_ecc_get_status)),
|
|
+};
|
|
+
|
|
+static int toshiba_spinand_detect(struct spinand_device *spinand)
|
|
+{
|
|
+ u8 *id = spinand->id.data;
|
|
+ int ret;
|
|
+
|
|
+ /*
|
|
+ * Toshiba SPI NAND read ID needs a dummy byte,
|
|
+ * so the first byte in id is garbage.
|
|
+ */
|
|
+ if (id[1] != SPINAND_MFR_TOSHIBA)
|
|
+ return 0;
|
|
+
|
|
+ ret = spinand_match_and_init(spinand, toshiba_spinand_table,
|
|
+ ARRAY_SIZE(toshiba_spinand_table),
|
|
+ id[2]);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = {
|
|
+ .detect = toshiba_spinand_detect,
|
|
+};
|
|
+
|
|
+const struct spinand_manufacturer toshiba_spinand_manufacturer = {
|
|
+ .id = SPINAND_MFR_TOSHIBA,
|
|
+ .name = "Toshiba",
|
|
+ .ops = &toshiba_spinand_manuf_ops,
|
|
+};
|
|
--- a/include/linux/mtd/spinand.h
|
|
+++ b/include/linux/mtd/spinand.h
|
|
@@ -196,6 +196,7 @@ struct spinand_manufacturer {
|
|
/* SPI NAND manufacturers */
|
|
extern const struct spinand_manufacturer macronix_spinand_manufacturer;
|
|
extern const struct spinand_manufacturer micron_spinand_manufacturer;
|
|
+extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
|
|
extern const struct spinand_manufacturer winbond_spinand_manufacturer;
|
|
|
|
/**
|