Commit 1666b815 authored by Miquel Raynal's avatar Miquel Raynal

mtd: rawnand: Add NV-DDR timings

Create the relevant ONFI NV-DDR timings structure and fill it with
default values from the ONFI specification.

Add the relevant structure entries and helpers.
Signed-off-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20210505213750.257417-9-miquel.raynal@bootlin.com
parent 7ce872d9
...@@ -292,6 +292,261 @@ static const struct nand_interface_config onfi_sdr_timings[] = { ...@@ -292,6 +292,261 @@ static const struct nand_interface_config onfi_sdr_timings[] = {
}, },
}; };
static const struct nand_interface_config onfi_nvddr_timings[] = {
/* Mode 0 */
{
.type = NAND_NVDDR_IFACE,
.timings.mode = 0,
.timings.nvddr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tAC_min = 3000,
.tAC_max = 25000,
.tADL_min = 400000,
.tCAD_min = 45000,
.tCAH_min = 10000,
.tCALH_min = 10000,
.tCALS_min = 10000,
.tCAS_min = 10000,
.tCEH_min = 20000,
.tCH_min = 10000,
.tCK_min = 50000,
.tCS_min = 35000,
.tDH_min = 5000,
.tDQSCK_min = 3000,
.tDQSCK_max = 25000,
.tDQSD_min = 0,
.tDQSD_max = 18000,
.tDQSHZ_max = 20000,
.tDQSQ_max = 5000,
.tDS_min = 5000,
.tDSC_min = 50000,
.tFEAT_max = 1000000,
.tITC_max = 1000000,
.tQHS_max = 6000,
.tRHW_min = 100000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWHR_min = 80000,
.tWRCK_min = 20000,
.tWW_min = 100000,
},
},
/* Mode 1 */
{
.type = NAND_NVDDR_IFACE,
.timings.mode = 1,
.timings.nvddr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tAC_min = 3000,
.tAC_max = 25000,
.tADL_min = 400000,
.tCAD_min = 45000,
.tCAH_min = 5000,
.tCALH_min = 5000,
.tCALS_min = 5000,
.tCAS_min = 5000,
.tCEH_min = 20000,
.tCH_min = 5000,
.tCK_min = 30000,
.tCS_min = 25000,
.tDH_min = 2500,
.tDQSCK_min = 3000,
.tDQSCK_max = 25000,
.tDQSD_min = 0,
.tDQSD_max = 18000,
.tDQSHZ_max = 20000,
.tDQSQ_max = 2500,
.tDS_min = 3000,
.tDSC_min = 30000,
.tFEAT_max = 1000000,
.tITC_max = 1000000,
.tQHS_max = 3000,
.tRHW_min = 100000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWHR_min = 80000,
.tWRCK_min = 20000,
.tWW_min = 100000,
},
},
/* Mode 2 */
{
.type = NAND_NVDDR_IFACE,
.timings.mode = 2,
.timings.nvddr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tAC_min = 3000,
.tAC_max = 25000,
.tADL_min = 400000,
.tCAD_min = 45000,
.tCAH_min = 4000,
.tCALH_min = 4000,
.tCALS_min = 4000,
.tCAS_min = 4000,
.tCEH_min = 20000,
.tCH_min = 4000,
.tCK_min = 20000,
.tCS_min = 15000,
.tDH_min = 1700,
.tDQSCK_min = 3000,
.tDQSCK_max = 25000,
.tDQSD_min = 0,
.tDQSD_max = 18000,
.tDQSHZ_max = 20000,
.tDQSQ_max = 1700,
.tDS_min = 2000,
.tDSC_min = 20000,
.tFEAT_max = 1000000,
.tITC_max = 1000000,
.tQHS_max = 2000,
.tRHW_min = 100000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWHR_min = 80000,
.tWRCK_min = 20000,
.tWW_min = 100000,
},
},
/* Mode 3 */
{
.type = NAND_NVDDR_IFACE,
.timings.mode = 3,
.timings.nvddr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tAC_min = 3000,
.tAC_max = 25000,
.tADL_min = 400000,
.tCAD_min = 45000,
.tCAH_min = 3000,
.tCALH_min = 3000,
.tCALS_min = 3000,
.tCAS_min = 3000,
.tCEH_min = 20000,
.tCH_min = 3000,
.tCK_min = 15000,
.tCS_min = 15000,
.tDH_min = 1300,
.tDQSCK_min = 3000,
.tDQSCK_max = 25000,
.tDQSD_min = 0,
.tDQSD_max = 18000,
.tDQSHZ_max = 20000,
.tDQSQ_max = 1300,
.tDS_min = 1500,
.tDSC_min = 15000,
.tFEAT_max = 1000000,
.tITC_max = 1000000,
.tQHS_max = 1500,
.tRHW_min = 100000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWHR_min = 80000,
.tWRCK_min = 20000,
.tWW_min = 100000,
},
},
/* Mode 4 */
{
.type = NAND_NVDDR_IFACE,
.timings.mode = 4,
.timings.nvddr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tAC_min = 3000,
.tAC_max = 25000,
.tADL_min = 400000,
.tCAD_min = 45000,
.tCAH_min = 2500,
.tCALH_min = 2500,
.tCALS_min = 2500,
.tCAS_min = 2500,
.tCEH_min = 20000,
.tCH_min = 2500,
.tCK_min = 12000,
.tCS_min = 15000,
.tDH_min = 1100,
.tDQSCK_min = 3000,
.tDQSCK_max = 25000,
.tDQSD_min = 0,
.tDQSD_max = 18000,
.tDQSHZ_max = 20000,
.tDQSQ_max = 1000,
.tDS_min = 1100,
.tDSC_min = 12000,
.tFEAT_max = 1000000,
.tITC_max = 1000000,
.tQHS_max = 1200,
.tRHW_min = 100000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWHR_min = 80000,
.tWRCK_min = 20000,
.tWW_min = 100000,
},
},
/* Mode 5 */
{
.type = NAND_NVDDR_IFACE,
.timings.mode = 5,
.timings.nvddr = {
.tCCS_min = 500000,
.tR_max = 200000000,
.tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
.tAC_min = 3000,
.tAC_max = 25000,
.tADL_min = 400000,
.tCAD_min = 45000,
.tCAH_min = 2000,
.tCALH_min = 2000,
.tCALS_min = 2000,
.tCAS_min = 2000,
.tCEH_min = 20000,
.tCH_min = 2000,
.tCK_min = 10000,
.tCS_min = 15000,
.tDH_min = 900,
.tDQSCK_min = 3000,
.tDQSCK_max = 25000,
.tDQSD_min = 0,
.tDQSD_max = 18000,
.tDQSHZ_max = 20000,
.tDQSQ_max = 850,
.tDS_min = 900,
.tDSC_min = 10000,
.tFEAT_max = 1000000,
.tITC_max = 1000000,
.tQHS_max = 1000,
.tRHW_min = 100000,
.tRR_min = 20000,
.tRST_max = 500000000,
.tWB_max = 100000,
.tWHR_min = 80000,
.tWRCK_min = 20000,
.tWW_min = 100000,
},
},
};
/* All NAND chips share the same reset data interface: SDR mode 0 */ /* All NAND chips share the same reset data interface: SDR mode 0 */
const struct nand_interface_config *nand_get_reset_interface_config(void) const struct nand_interface_config *nand_get_reset_interface_config(void)
{ {
......
...@@ -471,12 +471,100 @@ struct nand_sdr_timings { ...@@ -471,12 +471,100 @@ struct nand_sdr_timings {
u32 tWW_min; u32 tWW_min;
}; };
/**
* struct nand_nvddr_timings - NV-DDR NAND chip timings
*
* This struct defines the timing requirements of a NV-DDR NAND data interface.
* These information can be found in every NAND datasheets and the timings
* meaning are described in the ONFI specifications:
* https://media-www.micron.com/-/media/client/onfi/specs/onfi_4_1_gold.pdf
* (chapter 4.18.2 NV-DDR)
*
* All these timings are expressed in picoseconds.
*
* @tBERS_max: Block erase time
* @tCCS_min: Change column setup time
* @tPROG_max: Page program time
* @tR_max: Page read time
* @tAC_min: Access window of DQ[7:0] from CLK
* @tAC_max: Access window of DQ[7:0] from CLK
* @tADL_min: ALE to data loading time
* @tCAD_min: Command, Address, Data delay
* @tCAH_min: Command/Address DQ hold time
* @tCALH_min: W/R_n, CLE and ALE hold time
* @tCALS_min: W/R_n, CLE and ALE setup time
* @tCAS_min: Command/address DQ setup time
* @tCEH_min: CE# high hold time
* @tCH_min: CE# hold time
* @tCK_min: Average clock cycle time
* @tCS_min: CE# setup time
* @tDH_min: Data hold time
* @tDQSCK_min: Start of the access window of DQS from CLK
* @tDQSCK_max: End of the access window of DQS from CLK
* @tDQSD_min: Min W/R_n low to DQS/DQ driven by device
* @tDQSD_max: Max W/R_n low to DQS/DQ driven by device
* @tDQSHZ_max: W/R_n high to DQS/DQ tri-state by device
* @tDQSQ_max: DQS-DQ skew, DQS to last DQ valid, per access
* @tDS_min: Data setup time
* @tDSC_min: DQS cycle time
* @tFEAT_max: Busy time for Set Features and Get Features
* @tITC_max: Interface and Timing Mode Change time
* @tQHS_max: Data hold skew factor
* @tRHW_min: Data output cycle to command, address, or data input cycle
* @tRR_min: Ready to RE# low (data only)
* @tRST_max: Device reset time, measured from the falling edge of R/B# to the
* rising edge of R/B#.
* @tWB_max: WE# high to SR[6] low
* @tWHR_min: WE# high to RE# low
* @tWRCK_min: W/R_n low to data output cycle
* @tWW_min: WP# transition to WE# low
*/
struct nand_nvddr_timings {
u64 tBERS_max;
u32 tCCS_min;
u64 tPROG_max;
u64 tR_max;
u32 tAC_min;
u32 tAC_max;
u32 tADL_min;
u32 tCAD_min;
u32 tCAH_min;
u32 tCALH_min;
u32 tCALS_min;
u32 tCAS_min;
u32 tCEH_min;
u32 tCH_min;
u32 tCK_min;
u32 tCS_min;
u32 tDH_min;
u32 tDQSCK_min;
u32 tDQSCK_max;
u32 tDQSD_min;
u32 tDQSD_max;
u32 tDQSHZ_max;
u32 tDQSQ_max;
u32 tDS_min;
u32 tDSC_min;
u32 tFEAT_max;
u32 tITC_max;
u32 tQHS_max;
u32 tRHW_min;
u32 tRR_min;
u32 tRST_max;
u32 tWB_max;
u32 tWHR_min;
u32 tWRCK_min;
u32 tWW_min;
};
/** /**
* enum nand_interface_type - NAND interface type * enum nand_interface_type - NAND interface type
* @NAND_SDR_IFACE: Single Data Rate interface * @NAND_SDR_IFACE: Single Data Rate interface
* @NAND_NVDDR_IFACE: Double Data Rate interface
*/ */
enum nand_interface_type { enum nand_interface_type {
NAND_SDR_IFACE, NAND_SDR_IFACE,
NAND_NVDDR_IFACE,
}; };
/** /**
...@@ -485,6 +573,7 @@ enum nand_interface_type { ...@@ -485,6 +573,7 @@ enum nand_interface_type {
* @timings: The timing information * @timings: The timing information
* @timings.mode: Timing mode as defined in the specification * @timings.mode: Timing mode as defined in the specification
* @timings.sdr: Use it when @type is %NAND_SDR_IFACE. * @timings.sdr: Use it when @type is %NAND_SDR_IFACE.
* @timings.nvddr: Use it when @type is %NAND_NVDDR_IFACE.
*/ */
struct nand_interface_config { struct nand_interface_config {
enum nand_interface_type type; enum nand_interface_type type;
...@@ -492,6 +581,7 @@ struct nand_interface_config { ...@@ -492,6 +581,7 @@ struct nand_interface_config {
unsigned int mode; unsigned int mode;
union { union {
struct nand_sdr_timings sdr; struct nand_sdr_timings sdr;
struct nand_nvddr_timings nvddr;
}; };
} timings; } timings;
}; };
...@@ -505,6 +595,15 @@ static bool nand_interface_is_sdr(const struct nand_interface_config *conf) ...@@ -505,6 +595,15 @@ static bool nand_interface_is_sdr(const struct nand_interface_config *conf)
return conf->type == NAND_SDR_IFACE; return conf->type == NAND_SDR_IFACE;
} }
/**
* nand_interface_is_nvddr - get the interface type
* @conf: The data interface
*/
static bool nand_interface_is_nvddr(const struct nand_interface_config *conf)
{
return conf->type == NAND_NVDDR_IFACE;
}
/** /**
* nand_get_sdr_timings - get SDR timing from data interface * nand_get_sdr_timings - get SDR timing from data interface
* @conf: The data interface * @conf: The data interface
...@@ -518,6 +617,19 @@ nand_get_sdr_timings(const struct nand_interface_config *conf) ...@@ -518,6 +617,19 @@ nand_get_sdr_timings(const struct nand_interface_config *conf)
return &conf->timings.sdr; return &conf->timings.sdr;
} }
/**
* nand_get_nvddr_timings - get NV-DDR timing from data interface
* @conf: The data interface
*/
static inline const struct nand_nvddr_timings *
nand_get_nvddr_timings(const struct nand_interface_config *conf)
{
if (!nand_interface_is_nvddr(conf))
return ERR_PTR(-EINVAL);
return &conf->timings.nvddr;
}
/** /**
* struct nand_op_cmd_instr - Definition of a command instruction * struct nand_op_cmd_instr - Definition of a command instruction
* @opcode: the command to issue in one cycle * @opcode: the command to issue in one cycle
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment