mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 17:08:10 +00:00
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: Miquel Raynal <miquel.raynal@bootlin.com> Link: https://lore.kernel.org/linux-mtd/20210505213750.257417-9-miquel.raynal@bootlin.com
This commit is contained in:
parent
7ce872d9f5
commit
1666b815ad
2 changed files with 367 additions and 0 deletions
|
@ -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 */
|
||||
const struct nand_interface_config *nand_get_reset_interface_config(void)
|
||||
{
|
||||
|
|
|
@ -471,12 +471,100 @@ struct nand_sdr_timings {
|
|||
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
|
||||
* @NAND_SDR_IFACE: Single Data Rate interface
|
||||
* @NAND_NVDDR_IFACE: Double Data Rate interface
|
||||
*/
|
||||
enum nand_interface_type {
|
||||
NAND_SDR_IFACE,
|
||||
NAND_NVDDR_IFACE,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -485,6 +573,7 @@ enum nand_interface_type {
|
|||
* @timings: The timing information
|
||||
* @timings.mode: Timing mode as defined in the specification
|
||||
* @timings.sdr: Use it when @type is %NAND_SDR_IFACE.
|
||||
* @timings.nvddr: Use it when @type is %NAND_NVDDR_IFACE.
|
||||
*/
|
||||
struct nand_interface_config {
|
||||
enum nand_interface_type type;
|
||||
|
@ -492,6 +581,7 @@ struct nand_interface_config {
|
|||
unsigned int mode;
|
||||
union {
|
||||
struct nand_sdr_timings sdr;
|
||||
struct nand_nvddr_timings nvddr;
|
||||
};
|
||||
} timings;
|
||||
};
|
||||
|
@ -505,6 +595,15 @@ static bool nand_interface_is_sdr(const struct nand_interface_config *conf)
|
|||
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
|
||||
* @conf: The data interface
|
||||
|
@ -518,6 +617,19 @@ nand_get_sdr_timings(const struct nand_interface_config *conf)
|
|||
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
|
||||
* @opcode: the command to issue in one cycle
|
||||
|
|
Loading…
Reference in a new issue