2014-07-11 11:49:42 +04:00
/*
* Copyright ( C ) 2014 Free Electrons
*
* Author : Boris BREZILLON < boris . brezillon @ free - electrons . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
*/
# include <linux/kernel.h>
# include <linux/err.h>
# include <linux/export.h>
2017-08-04 18:29:10 +03:00
# include <linux/mtd/rawnand.h>
2014-07-11 11:49:42 +04:00
2018-07-14 13:23:54 +03:00
# define ONFI_DYN_TIMING_MAX U16_MAX
2016-09-15 11:32:47 +03:00
static const struct nand_data_interface onfi_sdr_timings [ ] = {
2014-07-11 11:49:42 +04:00
/* Mode 0 */
{
2016-09-15 11:32:47 +03:00
. type = NAND_SDR_IFACE ,
. timings . sdr = {
2016-10-01 11:24:02 +03:00
. tCCS_min = 500000 ,
. tR_max = 200000000 ,
2016-09-15 11:32:47 +03:00
. tADL_min = 400000 ,
. tALH_min = 20000 ,
. tALS_min = 50000 ,
. tAR_min = 25000 ,
. tCEA_max = 100000 ,
. tCEH_min = 20000 ,
. tCH_min = 20000 ,
. tCHZ_max = 100000 ,
. tCLH_min = 20000 ,
. tCLR_min = 20000 ,
. tCLS_min = 50000 ,
. tCOH_min = 0 ,
. tCS_min = 70000 ,
. tDH_min = 20000 ,
. tDS_min = 40000 ,
. tFEAT_max = 1000000 ,
. tIR_min = 10000 ,
. tITC_max = 1000000 ,
. tRC_min = 100000 ,
. tREA_max = 40000 ,
. tREH_min = 30000 ,
. tRHOH_min = 0 ,
. tRHW_min = 200000 ,
. tRHZ_max = 200000 ,
. tRLOH_min = 0 ,
. tRP_min = 50000 ,
. tRR_min = 40000 ,
. tRST_max = 250000000000ULL ,
. tWB_max = 200000 ,
. tWC_min = 100000 ,
. tWH_min = 30000 ,
. tWHR_min = 120000 ,
. tWP_min = 50000 ,
. tWW_min = 100000 ,
} ,
2014-07-11 11:49:42 +04:00
} ,
/* Mode 1 */
{
2016-09-15 11:32:47 +03:00
. type = NAND_SDR_IFACE ,
. timings . sdr = {
2016-10-01 11:24:02 +03:00
. tCCS_min = 500000 ,
. tR_max = 200000000 ,
2016-09-15 11:32:47 +03:00
. tADL_min = 400000 ,
. tALH_min = 10000 ,
. tALS_min = 25000 ,
. tAR_min = 10000 ,
. tCEA_max = 45000 ,
. tCEH_min = 20000 ,
. tCH_min = 10000 ,
. tCHZ_max = 50000 ,
. tCLH_min = 10000 ,
. tCLR_min = 10000 ,
. tCLS_min = 25000 ,
. tCOH_min = 15000 ,
. tCS_min = 35000 ,
. tDH_min = 10000 ,
. tDS_min = 20000 ,
. tFEAT_max = 1000000 ,
. tIR_min = 0 ,
. tITC_max = 1000000 ,
. tRC_min = 50000 ,
. tREA_max = 30000 ,
. tREH_min = 15000 ,
. tRHOH_min = 15000 ,
. tRHW_min = 100000 ,
. tRHZ_max = 100000 ,
. tRLOH_min = 0 ,
. tRP_min = 25000 ,
. tRR_min = 20000 ,
. tRST_max = 500000000 ,
. tWB_max = 100000 ,
. tWC_min = 45000 ,
. tWH_min = 15000 ,
. tWHR_min = 80000 ,
. tWP_min = 25000 ,
. tWW_min = 100000 ,
} ,
2014-07-11 11:49:42 +04:00
} ,
/* Mode 2 */
{
2016-09-15 11:32:47 +03:00
. type = NAND_SDR_IFACE ,
. timings . sdr = {
2016-10-01 11:24:02 +03:00
. tCCS_min = 500000 ,
. tR_max = 200000000 ,
2016-09-15 11:32:47 +03:00
. tADL_min = 400000 ,
. tALH_min = 10000 ,
. tALS_min = 15000 ,
. tAR_min = 10000 ,
. tCEA_max = 30000 ,
. tCEH_min = 20000 ,
. tCH_min = 10000 ,
. tCHZ_max = 50000 ,
. tCLH_min = 10000 ,
. tCLR_min = 10000 ,
. tCLS_min = 15000 ,
. tCOH_min = 15000 ,
. tCS_min = 25000 ,
. tDH_min = 5000 ,
. tDS_min = 15000 ,
. tFEAT_max = 1000000 ,
. tIR_min = 0 ,
. tITC_max = 1000000 ,
. tRC_min = 35000 ,
. tREA_max = 25000 ,
. tREH_min = 15000 ,
. tRHOH_min = 15000 ,
. tRHW_min = 100000 ,
. tRHZ_max = 100000 ,
. tRLOH_min = 0 ,
. tRR_min = 20000 ,
. tRST_max = 500000000 ,
. tWB_max = 100000 ,
. tRP_min = 17000 ,
. tWC_min = 35000 ,
. tWH_min = 15000 ,
. tWHR_min = 80000 ,
. tWP_min = 17000 ,
. tWW_min = 100000 ,
} ,
2014-07-11 11:49:42 +04:00
} ,
/* Mode 3 */
{
2016-09-15 11:32:47 +03:00
. type = NAND_SDR_IFACE ,
. timings . sdr = {
2016-10-01 11:24:02 +03:00
. tCCS_min = 500000 ,
. tR_max = 200000000 ,
2016-09-15 11:32:47 +03:00
. tADL_min = 400000 ,
. tALH_min = 5000 ,
. tALS_min = 10000 ,
. tAR_min = 10000 ,
. tCEA_max = 25000 ,
. tCEH_min = 20000 ,
. tCH_min = 5000 ,
. tCHZ_max = 50000 ,
. tCLH_min = 5000 ,
. tCLR_min = 10000 ,
. tCLS_min = 10000 ,
. tCOH_min = 15000 ,
. tCS_min = 25000 ,
. tDH_min = 5000 ,
. tDS_min = 10000 ,
. tFEAT_max = 1000000 ,
. tIR_min = 0 ,
. tITC_max = 1000000 ,
. tRC_min = 30000 ,
. tREA_max = 20000 ,
. tREH_min = 10000 ,
. tRHOH_min = 15000 ,
. tRHW_min = 100000 ,
. tRHZ_max = 100000 ,
. tRLOH_min = 0 ,
. tRP_min = 15000 ,
. tRR_min = 20000 ,
. tRST_max = 500000000 ,
. tWB_max = 100000 ,
. tWC_min = 30000 ,
. tWH_min = 10000 ,
. tWHR_min = 80000 ,
. tWP_min = 15000 ,
. tWW_min = 100000 ,
} ,
2014-07-11 11:49:42 +04:00
} ,
/* Mode 4 */
{
2016-09-15 11:32:47 +03:00
. type = NAND_SDR_IFACE ,
. timings . sdr = {
2016-10-01 11:24:02 +03:00
. tCCS_min = 500000 ,
. tR_max = 200000000 ,
2016-09-15 11:32:47 +03:00
. tADL_min = 400000 ,
. tALH_min = 5000 ,
. tALS_min = 10000 ,
. tAR_min = 10000 ,
. tCEA_max = 25000 ,
. tCEH_min = 20000 ,
. tCH_min = 5000 ,
. tCHZ_max = 30000 ,
. tCLH_min = 5000 ,
. tCLR_min = 10000 ,
. tCLS_min = 10000 ,
. tCOH_min = 15000 ,
. tCS_min = 20000 ,
. tDH_min = 5000 ,
. tDS_min = 10000 ,
. tFEAT_max = 1000000 ,
. tIR_min = 0 ,
. tITC_max = 1000000 ,
. tRC_min = 25000 ,
. tREA_max = 20000 ,
. tREH_min = 10000 ,
. tRHOH_min = 15000 ,
. tRHW_min = 100000 ,
. tRHZ_max = 100000 ,
. tRLOH_min = 5000 ,
. tRP_min = 12000 ,
. tRR_min = 20000 ,
. tRST_max = 500000000 ,
. tWB_max = 100000 ,
. tWC_min = 25000 ,
. tWH_min = 10000 ,
. tWHR_min = 80000 ,
. tWP_min = 12000 ,
. tWW_min = 100000 ,
} ,
2014-07-11 11:49:42 +04:00
} ,
/* Mode 5 */
{
2016-09-15 11:32:47 +03:00
. type = NAND_SDR_IFACE ,
. timings . sdr = {
2016-10-01 11:24:02 +03:00
. tCCS_min = 500000 ,
. tR_max = 200000000 ,
2016-09-15 11:32:47 +03:00
. tADL_min = 400000 ,
. tALH_min = 5000 ,
. tALS_min = 10000 ,
. tAR_min = 10000 ,
. tCEA_max = 25000 ,
. tCEH_min = 20000 ,
. tCH_min = 5000 ,
. tCHZ_max = 30000 ,
. tCLH_min = 5000 ,
. tCLR_min = 10000 ,
. tCLS_min = 10000 ,
. tCOH_min = 15000 ,
. tCS_min = 15000 ,
. tDH_min = 5000 ,
. tDS_min = 7000 ,
. tFEAT_max = 1000000 ,
. tIR_min = 0 ,
. tITC_max = 1000000 ,
. tRC_min = 20000 ,
. tREA_max = 16000 ,
. tREH_min = 7000 ,
. tRHOH_min = 15000 ,
. tRHW_min = 100000 ,
. tRHZ_max = 100000 ,
. tRLOH_min = 5000 ,
. tRP_min = 10000 ,
. tRR_min = 20000 ,
. tRST_max = 500000000 ,
. tWB_max = 100000 ,
. tWC_min = 20000 ,
. tWH_min = 7000 ,
. tWHR_min = 80000 ,
. tWP_min = 10000 ,
. tWW_min = 100000 ,
} ,
2014-07-11 11:49:42 +04:00
} ,
} ;
2016-09-15 11:32:48 +03:00
/**
2017-11-30 20:01:31 +03:00
* onfi_fill_data_interface - [ NAND Interface ] Initialize a data interface from
2016-09-15 11:32:48 +03:00
* given ONFI mode
* @ mode : The ONFI timing mode
*/
2017-11-30 20:01:31 +03:00
int onfi_fill_data_interface ( struct nand_chip * chip ,
2016-09-15 11:32:48 +03:00
enum nand_data_interface_type type ,
int timing_mode )
{
2017-11-30 20:01:31 +03:00
struct nand_data_interface * iface = & chip - > data_interface ;
2018-07-25 16:31:52 +03:00
struct onfi_params * onfi = chip - > parameters . onfi ;
2017-11-30 20:01:31 +03:00
2016-09-15 11:32:48 +03:00
if ( type ! = NAND_SDR_IFACE )
return - EINVAL ;
if ( timing_mode < 0 | | timing_mode > = ARRAY_SIZE ( onfi_sdr_timings ) )
return - EINVAL ;
* iface = onfi_sdr_timings [ timing_mode ] ;
/*
2016-10-01 11:24:02 +03:00
* Initialize timings that cannot be deduced from timing mode :
2018-07-14 13:23:54 +03:00
* tPROG , tBERS , tR and tCCS .
2016-09-15 11:32:48 +03:00
* These information are part of the ONFI parameter page .
*/
2018-07-25 16:31:52 +03:00
if ( onfi ) {
2016-10-01 11:24:02 +03:00
struct nand_sdr_timings * timings = & iface - > timings . sdr ;
/* microseconds -> picoseconds */
2018-07-25 16:31:52 +03:00
timings - > tPROG_max = 1000000ULL * onfi - > tPROG ;
timings - > tBERS_max = 1000000ULL * onfi - > tBERS ;
timings - > tR_max = 1000000ULL * onfi - > tR ;
2016-10-01 11:24:02 +03:00
/* nanoseconds -> picoseconds */
2018-07-25 16:31:52 +03:00
timings - > tCCS_min = 1000UL * onfi - > tCCS ;
2018-07-14 13:23:54 +03:00
} else {
struct nand_sdr_timings * timings = & iface - > timings . sdr ;
/*
* For non - ONFI chips we use the highest possible value for
* tPROG and tBERS . tR and tCCS will take the default values
* precised in the ONFI specification for timing mode 0 ,
* respectively 200u s and 500 ns .
*/
/* microseconds -> picoseconds */
timings - > tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX ;
timings - > tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX ;
timings - > tR_max = 1000000ULL * 200000000ULL ;
/* nanoseconds -> picoseconds */
timings - > tCCS_min = 1000UL * 500000 ;
2016-10-01 11:24:02 +03:00
}
2016-09-15 11:32:48 +03:00
return 0 ;
}
2017-11-30 20:01:31 +03:00
EXPORT_SYMBOL ( onfi_fill_data_interface ) ;