* [PATCH] mtd: rawnand: Non ONFI specialized timing support
@ 2020-04-22 12:18 Rickard Andersson
2020-05-12 19:09 ` Miquel Raynal
0 siblings, 1 reply; 4+ messages in thread
From: Rickard Andersson @ 2020-04-22 12:18 UTC (permalink / raw)
To: linux-mtd, miquel.raynal, richard, vigneshr, s.hauer; +Cc: rickaran
From: Rickard x Andersson <rickaran@axis.com>
The Kioxia/Toshiba TH58NVG2S3HBAI4 NAND memory is not a
ONFI compliant memory. The timings of that memory are quite
close to ONFI mode 4 but is breaking that spec.
This patch adds a special table with timings that can be
used for non ONFI memories.
Erase block read speed is increased from 6739 KiB/s to
13260 KiB/s. Erase block write speed is increased from
3004 KiB/s to 3872 KiB/s.
Tested on IMX6ULL which has a NAND controller supporting
EDO mode.
Signed-off-by: Rickard x Andersson <rickaran@axis.com>
---
drivers/mtd/nand/raw/internals.h | 3 +-
drivers/mtd/nand/raw/nand_base.c | 73 +++++++++++++++++++++++++++++++++----
drivers/mtd/nand/raw/nand_ids.c | 4 ++
drivers/mtd/nand/raw/nand_timings.c | 66 +++++++++++++++++++++++++++++++--
include/linux/mtd/rawnand.h | 24 ++++++++++++
5 files changed, 157 insertions(+), 13 deletions(-)
diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h
index fbf6ca015cd7..4fcb9f87caaf 100644
--- a/drivers/mtd/nand/raw/internals.h
+++ b/drivers/mtd/nand/raw/internals.h
@@ -81,7 +81,8 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
int allowbbt);
int onfi_fill_data_interface(struct nand_chip *chip,
enum nand_data_interface_type type,
- int timing_mode);
+ int timing_mode,
+ enum non_onfi_spec_timing spec_timing);
int nand_get_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
int nand_set_features(struct nand_chip *chip, int addr, u8 *subfeature_param);
int nand_read_page_raw_notsupp(struct nand_chip *chip, u8 *buf,
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index ddd396e93e32..8980e42ec6bd 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -793,7 +793,8 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr)
* timings to timing mode 0.
*/
- onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
+ onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0,
+ NON_ONFI_TIMING_NOT_USED);
ret = chip->controller->ops->setup_data_interface(chip, chipnr,
&chip->data_interface);
if (ret)
@@ -875,6 +876,51 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
}
/**
+ * nand_handle_non_onfi_spec_timings - Handle non ONFI timings
+ * @chip: The NAND chip
+ *
+ * Returns 0 for success or negative error code otherwise.
+ */
+static int nand_handle_non_onfi_spec_timings(struct nand_chip *chip)
+{
+ int ret;
+
+ if (chip->spec_timing == NON_ONFI_TIMING_NOT_USED)
+ return -EINVAL;
+
+ if (chip->onfi_timing_mode_default)
+ return -EINVAL;
+
+ ret = onfi_fill_data_interface(chip,
+ NAND_SDR_IFACE,
+ chip->onfi_timing_mode_default,
+ chip->spec_timing);
+ if (ret)
+ return ret;
+ /*
+ * Pass NAND_DATA_IFACE_CHECK_ONLY to only check if the
+ * controller supports the requested timings.
+ */
+ ret = chip->controller->ops->setup_data_interface(chip,
+ NAND_DATA_IFACE_CHECK_ONLY,
+ &chip->data_interface);
+
+ if (ret) {
+ /*
+ * Settings were not supported by the controller,
+ * restore safe settings.
+ */
+ chip->spec_timing = NON_ONFI_TIMING_NOT_USED;
+ ret = onfi_fill_data_interface(chip,
+ NAND_SDR_IFACE,
+ chip->onfi_timing_mode_default,
+ chip->spec_timing);
+ }
+
+ return ret;
+}
+
+/**
* nand_init_data_interface - find the best data interface and timings
* @chip: The NAND chip
*
@@ -882,9 +928,11 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
* and the driver.
* First tries to retrieve supported timing modes from ONFI information,
* and if the NAND chip does not support ONFI, relies on the
- * ->onfi_timing_mode_default specified in the nand_ids table. After this
- * function nand_chip->data_interface is initialized with the best timing mode
- * available.
+ * ->onfi_timing_mode_default specified in the nand_ids table. If
+ * onfi_timing_mode_default is not provided then ->spec_timing
+ * will be used if set.
+ * After this function nand_chip->data_interface is initialized with the
+ * best timing mode available.
*
* Returns 0 for success or negative error code otherwise.
*/
@@ -903,14 +951,21 @@ static int nand_init_data_interface(struct nand_chip *chip)
if (chip->parameters.onfi) {
modes = chip->parameters.onfi->async_timing_mode;
} else {
- if (!chip->onfi_timing_mode_default)
- return 0;
+ if (!chip->onfi_timing_mode_default) {
+ if (chip->spec_timing) {
+ ret = nand_handle_non_onfi_spec_timings(chip);
+ if (ret)
+ return ret;
+ }
+ return 0;
+ }
modes = GENMASK(chip->onfi_timing_mode_default, 0);
}
for (mode = fls(modes) - 1; mode >= 0; mode--) {
- ret = onfi_fill_data_interface(chip, NAND_SDR_IFACE, mode);
+ ret = onfi_fill_data_interface(chip, NAND_SDR_IFACE, mode,
+ NON_ONFI_TIMING_NOT_USED);
if (ret)
continue;
@@ -4564,6 +4619,7 @@ static bool find_full_id_nand(struct nand_chip *chip,
chip->ecc_step_ds = NAND_ECC_STEP(type);
chip->onfi_timing_mode_default =
type->onfi_timing_mode_default;
+ chip->spec_timing = type->spec_timing;
chip->parameters.model = kstrdup(type->name, GFP_KERNEL);
if (!chip->parameters.model)
@@ -4981,7 +5037,8 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
mutex_init(&chip->lock);
/* Enforce the right timings for reset/detection */
- onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
+ onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0,
+ NON_ONFI_TIMING_NOT_USED);
ret = nand_dt_init(chip);
if (ret)
diff --git a/drivers/mtd/nand/raw/nand_ids.c b/drivers/mtd/nand/raw/nand_ids.c
index ea5a342cd91e..b1eb508a74e0 100644
--- a/drivers/mtd/nand/raw/nand_ids.c
+++ b/drivers/mtd/nand/raw/nand_ids.c
@@ -56,6 +56,10 @@ struct nand_flash_dev nand_flash_ids[] = {
{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
NAND_ECC_INFO(40, SZ_1K), 4 },
+ {"TH58NVG2S3HBAI4 4G 3.3V 8-bit",
+ { .id = {0x98, 0xdc, 0x91, 0x15, 0x76} },
+ SZ_2K, SZ_512, SZ_128K, 0, 5, 128, NAND_ECC_INFO(8, SZ_512),
+ 0, NON_ONFI_TIMING_1},
LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c
index bea3062d71d6..0de07da36485 100644
--- a/drivers/mtd/nand/raw/nand_timings.c
+++ b/drivers/mtd/nand/raw/nand_timings.c
@@ -271,14 +271,67 @@ static const struct nand_data_interface onfi_sdr_timings[] = {
},
};
+static const struct nand_data_interface non_onfi_spec_sdr_timings[] = {
+ /*
+ * Chosen by enum non_onfi_spec_timing = NON_ONFI_TIMING_1
+ *
+ * Data below is obtained from KIOXIA/Toshiba TH58NVG2S3HBAI4
+ */
+ {
+ .type = NAND_SDR_IFACE,
+ .timings.sdr = {
+ .tCCS_min = 500000,
+ .tR_max = 200000000,
+ .tADL_min = 400000,
+ .tALH_min = 5000,
+ .tALS_min = 12000,
+ .tAR_min = 10000,
+ .tCEA_max = 25000,
+ .tCEH_min = 20000,
+ .tCH_min = 5000,
+ .tCHZ_max = 20000,
+ .tCLH_min = 5000,
+ .tCLR_min = 10000,
+ .tCLS_min = 12000,
+ .tCOH_min = 0,
+ .tCS_min = 20000,
+ .tDH_min = 5000,
+ .tDS_min = 12000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 25000,
+ .tREA_max = 20000,
+ .tREH_min = 10000,
+ .tRHOH_min = 25000,
+ .tRHW_min = 30000,
+ .tRHZ_max = 60000,
+ .tRLOH_min = 5000,
+ .tRP_min = 12000,
+ .tRR_min = 20000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tWC_min = 25000,
+ .tWH_min = 10000,
+ .tWHR_min = 60000,
+ .tWP_min = 12000,
+ .tWW_min = 100000,
+ },
+ },
+};
+
/**
* onfi_fill_data_interface - [NAND Interface] Initialize a data interface from
* given ONFI mode
- * @mode: The ONFI timing mode
+ * @chip: The NAND chip
+ * @onfi_timing_mode: The ONFI timing mode
+ * @type: Timing type
+ * @spec_timing: Special timings to be used for non ONFI NAND memories
*/
int onfi_fill_data_interface(struct nand_chip *chip,
enum nand_data_interface_type type,
- int timing_mode)
+ int onfi_timing_mode,
+ enum non_onfi_spec_timing spec_timing)
{
struct nand_data_interface *iface = &chip->data_interface;
struct onfi_params *onfi = chip->parameters.onfi;
@@ -286,10 +339,15 @@ int onfi_fill_data_interface(struct nand_chip *chip,
if (type != NAND_SDR_IFACE)
return -EINVAL;
- if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings))
+ if (onfi_timing_mode < 0 ||
+ onfi_timing_mode >= ARRAY_SIZE(onfi_sdr_timings))
return -EINVAL;
- *iface = onfi_sdr_timings[timing_mode];
+ if ((spec_timing > 0) &&
+ (spec_timing <= ARRAY_SIZE(non_onfi_spec_sdr_timings)))
+ *iface = non_onfi_spec_sdr_timings[spec_timing - 1];
+ else
+ *iface = onfi_sdr_timings[onfi_timing_mode];
/*
* Initialize timings that cannot be deduced from timing mode:
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index b7445a44a814..329eff0951ed 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -961,6 +961,17 @@ struct nand_legacy {
};
/**
+ * enum non_onfi_spec_timing - Special timing that can be used for
+ * non ONFI NAND.
+ * @NON_ONFI_TIMING_NOT_USED: No special timings
+ * @NON_ONFI_TIMING_1: Special timing 1
+ */
+enum non_onfi_spec_timing {
+ NON_ONFI_TIMING_NOT_USED,
+ NON_ONFI_TIMING_1,
+};
+
+/**
* struct nand_chip - NAND Private Flash Chip Data
* @mtd: MTD device registered to the MTD framework
* @legacy: All legacy fields/hooks. If you develop a new driver,
@@ -1001,6 +1012,10 @@ struct nand_legacy {
* set to the actually used ONFI mode if the chip is
* ONFI compliant or deduced from the datasheet if
* the NAND chip is not ONFI compliant.
+ * @spec_timing: [INTERN] This field is set to choose the special
+ * non onfi timings. This is used if the chip is not
+ * ONFI compliant and the timings does not correspond
+ * to any of the ONFI modes.
* @numchips: [INTERN] number of physical chips
* @chipsize: [INTERN] the size of one chip for multichip arrays
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
@@ -1065,6 +1080,7 @@ struct nand_chip {
uint16_t ecc_strength_ds;
uint16_t ecc_step_ds;
int onfi_timing_mode_default;
+ enum non_onfi_spec_timing spec_timing;
int badblockpos;
int badblockbits;
@@ -1202,6 +1218,13 @@ static inline void *nand_get_manufacturer_data(struct nand_chip *chip)
* @onfi_timing_mode_default: the default ONFI timing mode entered after a NAND
* reset. Should be deduced from timings described
* in the datasheet.
+ * @spec_timing: Alternative timing table to be used after a NAND reset.
+ * This can be used for non ONFI NANDs that does not have
+ * timings that correspond well to the ONFI timing modes.
+ * This value references non_onfi_spec_sdr_timings[] in
+ * nand_timings.c.
+ * Should be deduced from timings described
+ * in the datasheet.
*
*/
struct nand_flash_dev {
@@ -1224,6 +1247,7 @@ struct nand_flash_dev {
uint16_t step_ds;
} ecc;
int onfi_timing_mode_default;
+ enum non_onfi_spec_timing spec_timing;
};
int nand_create_bbt(struct nand_chip *chip);
--
2.11.0
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] mtd: rawnand: Non ONFI specialized timing support
2020-04-22 12:18 [PATCH] mtd: rawnand: Non ONFI specialized timing support Rickard Andersson
@ 2020-05-12 19:09 ` Miquel Raynal
2020-05-13 8:48 ` Miquel Raynal
0 siblings, 1 reply; 4+ messages in thread
From: Miquel Raynal @ 2020-05-12 19:09 UTC (permalink / raw)
To: Rickard Andersson; +Cc: richard, s.hauer, linux-mtd, vigneshr, Boris Brezillon
Hi Rickard,
+ boris
Rickard Andersson <rickaran@axis.com> wrote on Wed, 22 Apr 2020
14:18:00 +0200:
> From: Rickard x Andersson <rickaran@axis.com>
>
> The Kioxia/Toshiba TH58NVG2S3HBAI4 NAND memory is not a
> ONFI compliant memory. The timings of that memory are quite
> close to ONFI mode 4 but is breaking that spec.
>
> This patch adds a special table with timings that can be
> used for non ONFI memories.
>
> Erase block read speed is increased from 6739 KiB/s to
> 13260 KiB/s. Erase block write speed is increased from
> 3004 KiB/s to 3872 KiB/s.
>
> Tested on IMX6ULL which has a NAND controller supporting
> EDO mode.
I am convinced about the idea of tweaking non-ONFI timings on a
per-chip basis to enhance their throughput, but I think we should do
this another way.
What we could have is a way, for NAND manufacturer drivers, to overload
the timings. This way, Kioxia timings remain in the Toshiba driver.
I quickly prepared a small series [1], it is untested but it will
hopefully help you adapt your patch. You just have to set the
chip->init_data_interface() hook from the Toshiba driver at init time.
This hook is supposed to update the whole data interface structure and
also call chip->controller.ops() to verify it is supported by the
controller.
[1] https://github.com/miquelraynal/linux/tree/perso/nand-next/timings
Thanks,
Miquèl
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] mtd: rawnand: Non ONFI specialized timing support
2020-05-12 19:09 ` Miquel Raynal
@ 2020-05-13 8:48 ` Miquel Raynal
2020-05-14 9:04 ` SV: " Rickard X Andersson
0 siblings, 1 reply; 4+ messages in thread
From: Miquel Raynal @ 2020-05-13 8:48 UTC (permalink / raw)
To: Rickard Andersson; +Cc: richard, s.hauer, linux-mtd, vigneshr, Boris Brezillon
Hi Rickard,
Miquel Raynal <miquel.raynal@bootlin.com> wrote on Tue, 12 May 2020
21:09:33 +0200:
> Hi Rickard,
>
> + boris
>
> Rickard Andersson <rickaran@axis.com> wrote on Wed, 22 Apr 2020
> 14:18:00 +0200:
>
> > From: Rickard x Andersson <rickaran@axis.com>
> >
> > The Kioxia/Toshiba TH58NVG2S3HBAI4 NAND memory is not a
> > ONFI compliant memory. The timings of that memory are quite
> > close to ONFI mode 4 but is breaking that spec.
> >
> > This patch adds a special table with timings that can be
> > used for non ONFI memories.
> >
> > Erase block read speed is increased from 6739 KiB/s to
> > 13260 KiB/s. Erase block write speed is increased from
> > 3004 KiB/s to 3872 KiB/s.
> >
> > Tested on IMX6ULL which has a NAND controller supporting
> > EDO mode.
>
> I am convinced about the idea of tweaking non-ONFI timings on a
> per-chip basis to enhance their throughput, but I think we should do
> this another way.
>
> What we could have is a way, for NAND manufacturer drivers, to overload
> the timings. This way, Kioxia timings remain in the Toshiba driver.
>
> I quickly prepared a small series [1], it is untested but it will
> hopefully help you adapt your patch. You just have to set the
> chip->init_data_interface() hook from the Toshiba driver at init time.
> This hook is supposed to update the whole data interface structure and
> also call chip->controller.ops() to verify it is supported by the
> controller.
>
> [1] https://github.com/miquelraynal/linux/tree/perso/nand-next/timings
Boris commented on Github, so I updated the code and pushed -f
Thanks,
Miquèl
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply [flat|nested] 4+ messages in thread
* SV: [PATCH] mtd: rawnand: Non ONFI specialized timing support
2020-05-13 8:48 ` Miquel Raynal
@ 2020-05-14 9:04 ` Rickard X Andersson
0 siblings, 0 replies; 4+ messages in thread
From: Rickard X Andersson @ 2020-05-14 9:04 UTC (permalink / raw)
To: Miquel Raynal; +Cc: richard, s.hauer, linux-mtd, vigneshr, Boris Brezillon
Hi,
Thanks for the feedback. I have now created a new patchset on top of your patches. Will send it very soon.
BR
Rickard Andersson
________________________________________
Från: Miquel Raynal <miquel.raynal@bootlin.com>
Skickat: den 13 maj 2020 10:48
Till: Rickard X Andersson
Kopia: linux-mtd@lists.infradead.org; richard@nod.at; vigneshr@ti.com; s.hauer@pengutronix.de; Boris Brezillon
Ämne: Re: [PATCH] mtd: rawnand: Non ONFI specialized timing support
Hi Rickard,
Miquel Raynal <miquel.raynal@bootlin.com> wrote on Tue, 12 May 2020
21:09:33 +0200:
> Hi Rickard,
>
> + boris
>
> Rickard Andersson <rickaran@axis.com> wrote on Wed, 22 Apr 2020
> 14:18:00 +0200:
>
> > From: Rickard x Andersson <rickaran@axis.com>
> >
> > The Kioxia/Toshiba TH58NVG2S3HBAI4 NAND memory is not a
> > ONFI compliant memory. The timings of that memory are quite
> > close to ONFI mode 4 but is breaking that spec.
> >
> > This patch adds a special table with timings that can be
> > used for non ONFI memories.
> >
> > Erase block read speed is increased from 6739 KiB/s to
> > 13260 KiB/s. Erase block write speed is increased from
> > 3004 KiB/s to 3872 KiB/s.
> >
> > Tested on IMX6ULL which has a NAND controller supporting
> > EDO mode.
>
> I am convinced about the idea of tweaking non-ONFI timings on a
> per-chip basis to enhance their throughput, but I think we should do
> this another way.
>
> What we could have is a way, for NAND manufacturer drivers, to overload
> the timings. This way, Kioxia timings remain in the Toshiba driver.
>
> I quickly prepared a small series [1], it is untested but it will
> hopefully help you adapt your patch. You just have to set the
> chip->init_data_interface() hook from the Toshiba driver at init time.
> This hook is supposed to update the whole data interface structure and
> also call chip->controller.ops() to verify it is supported by the
> controller.
>
> [1] https://github.com/miquelraynal/linux/tree/perso/nand-next/timings
Boris commented on Github, so I updated the code and pushed -f
Thanks,
Miquèl
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2020-05-14 9:04 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-22 12:18 [PATCH] mtd: rawnand: Non ONFI specialized timing support Rickard Andersson
2020-05-12 19:09 ` Miquel Raynal
2020-05-13 8:48 ` Miquel Raynal
2020-05-14 9:04 ` SV: " Rickard X Andersson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).