summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/mtd/nand/raw/nand_onfi.c1
-rw-r--r--drivers/mtd/nand/raw/nand_timings.c41
-rw-r--r--include/linux/mtd/onfi.h2
3 files changed, 44 insertions, 0 deletions
diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c
index f7a4a0573fe7..8e4677f2ba76 100644
--- a/drivers/mtd/nand/raw/nand_onfi.c
+++ b/drivers/mtd/nand/raw/nand_onfi.c
@@ -315,6 +315,7 @@ int nand_onfi_detect(struct nand_chip *chip)
onfi->tBERS = le16_to_cpu(p->t_bers);
onfi->tR = le16_to_cpu(p->t_r);
onfi->tCCS = le16_to_cpu(p->t_ccs);
+ onfi->fast_tCAD = p->nvddr_nvddr2_features & BIT(0);
onfi->sdr_timing_modes = le16_to_cpu(p->sdr_timing_modes);
if (p->features & ONFI_FEATURE_NV_DDR)
onfi->nvddr_timing_modes = p->nvddr_timing_modes;
diff --git a/drivers/mtd/nand/raw/nand_timings.c b/drivers/mtd/nand/raw/nand_timings.c
index fb483e696cb9..8eaa132c3900 100644
--- a/drivers/mtd/nand/raw/nand_timings.c
+++ b/drivers/mtd/nand/raw/nand_timings.c
@@ -637,6 +637,45 @@ static void onfi_fill_sdr_interface_config(struct nand_chip *chip,
}
/**
+ * onfi_fill_nvddr_interface_config - Initialize a NVDDR interface config from a
+ * given ONFI mode
+ * @chip: The NAND chip
+ * @iface: The interface configuration to fill
+ * @timing_mode: The ONFI timing mode
+ */
+static void onfi_fill_nvddr_interface_config(struct nand_chip *chip,
+ struct nand_interface_config *iface,
+ unsigned int timing_mode)
+{
+ struct onfi_params *onfi = chip->parameters.onfi;
+
+ if (WARN_ON(timing_mode >= ARRAY_SIZE(onfi_nvddr_timings)))
+ return;
+
+ *iface = onfi_nvddr_timings[timing_mode];
+
+ /*
+ * Initialize timings that cannot be deduced from timing mode:
+ * tPROG, tBERS, tR, tCCS and tCAD.
+ * These information are part of the ONFI parameter page.
+ */
+ if (onfi) {
+ struct nand_nvddr_timings *timings = &iface->timings.nvddr;
+
+ /* microseconds -> picoseconds */
+ timings->tPROG_max = 1000000ULL * onfi->tPROG;
+ timings->tBERS_max = 1000000ULL * onfi->tBERS;
+ timings->tR_max = 1000000ULL * onfi->tR;
+
+ /* nanoseconds -> picoseconds */
+ timings->tCCS_min = 1000UL * onfi->tCCS;
+
+ if (onfi->fast_tCAD)
+ timings->tCAD_min = 25000;
+ }
+}
+
+/**
* onfi_fill_interface_config - Initialize an interface config from a given
* ONFI mode
* @chip: The NAND chip
@@ -651,4 +690,6 @@ void onfi_fill_interface_config(struct nand_chip *chip,
{
if (type == NAND_SDR_IFACE)
return onfi_fill_sdr_interface_config(chip, iface, timing_mode);
+ else
+ return onfi_fill_nvddr_interface_config(chip, iface, timing_mode);
}
diff --git a/include/linux/mtd/onfi.h b/include/linux/mtd/onfi.h
index 14e66a49557e..a9677bf1e47e 100644
--- a/include/linux/mtd/onfi.h
+++ b/include/linux/mtd/onfi.h
@@ -162,6 +162,7 @@ struct onfi_ext_param_page {
* @tBERS: Block erase time
* @tR: Page read time
* @tCCS: Change column setup time
+ * @fast_tCAD: Command/Address/Data slow or fast delay (NV-DDR only)
* @sdr_timing_modes: Supported asynchronous/SDR timing modes
* @nvddr_timing_modes: Supported source synchronous/NV-DDR timing modes
* @vendor_revision: Vendor specific revision number
@@ -173,6 +174,7 @@ struct onfi_params {
u16 tBERS;
u16 tR;
u16 tCCS;
+ bool fast_tCAD;
u16 sdr_timing_modes;
u16 nvddr_timing_modes;
u16 vendor_revision;