123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (C) 2014 Free Electrons
- *
- * Author: Boris BREZILLON <[email protected]>
- */
- #include <linux/kernel.h>
- #include <linux/err.h>
- #include <linux/export.h>
- #include "internals.h"
- #define ONFI_DYN_TIMING_MAX U16_MAX
- /*
- * 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 200us and 500ns.
- *
- * These four values are tweaked to be more accurate in the case of ONFI chips.
- */
- static const struct nand_interface_config onfi_sdr_timings[] = {
- /* Mode 0 */
- {
- .type = NAND_SDR_IFACE,
- .timings.mode = 0,
- .timings.sdr = {
- .tCCS_min = 500000,
- .tR_max = 200000000,
- .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
- .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
- .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,
- },
- },
- /* Mode 1 */
- {
- .type = NAND_SDR_IFACE,
- .timings.mode = 1,
- .timings.sdr = {
- .tCCS_min = 500000,
- .tR_max = 200000000,
- .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
- .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
- .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,
- },
- },
- /* Mode 2 */
- {
- .type = NAND_SDR_IFACE,
- .timings.mode = 2,
- .timings.sdr = {
- .tCCS_min = 500000,
- .tR_max = 200000000,
- .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
- .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
- .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,
- },
- },
- /* Mode 3 */
- {
- .type = NAND_SDR_IFACE,
- .timings.mode = 3,
- .timings.sdr = {
- .tCCS_min = 500000,
- .tR_max = 200000000,
- .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
- .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
- .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,
- },
- },
- /* Mode 4 */
- {
- .type = NAND_SDR_IFACE,
- .timings.mode = 4,
- .timings.sdr = {
- .tCCS_min = 500000,
- .tR_max = 200000000,
- .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
- .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
- .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,
- },
- },
- /* Mode 5 */
- {
- .type = NAND_SDR_IFACE,
- .timings.mode = 5,
- .timings.sdr = {
- .tCCS_min = 500000,
- .tR_max = 200000000,
- .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
- .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX,
- .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,
- },
- },
- };
- 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)
- {
- return &onfi_sdr_timings[0];
- }
- /**
- * onfi_find_closest_sdr_mode - Derive the closest ONFI SDR timing mode given a
- * set of timings
- * @spec_timings: the timings to challenge
- */
- unsigned int
- onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings)
- {
- const struct nand_sdr_timings *onfi_timings;
- int mode;
- for (mode = ARRAY_SIZE(onfi_sdr_timings) - 1; mode > 0; mode--) {
- onfi_timings = &onfi_sdr_timings[mode].timings.sdr;
- if (spec_timings->tCCS_min <= onfi_timings->tCCS_min &&
- spec_timings->tADL_min <= onfi_timings->tADL_min &&
- spec_timings->tALH_min <= onfi_timings->tALH_min &&
- spec_timings->tALS_min <= onfi_timings->tALS_min &&
- spec_timings->tAR_min <= onfi_timings->tAR_min &&
- spec_timings->tCEH_min <= onfi_timings->tCEH_min &&
- spec_timings->tCH_min <= onfi_timings->tCH_min &&
- spec_timings->tCLH_min <= onfi_timings->tCLH_min &&
- spec_timings->tCLR_min <= onfi_timings->tCLR_min &&
- spec_timings->tCLS_min <= onfi_timings->tCLS_min &&
- spec_timings->tCOH_min <= onfi_timings->tCOH_min &&
- spec_timings->tCS_min <= onfi_timings->tCS_min &&
- spec_timings->tDH_min <= onfi_timings->tDH_min &&
- spec_timings->tDS_min <= onfi_timings->tDS_min &&
- spec_timings->tIR_min <= onfi_timings->tIR_min &&
- spec_timings->tRC_min <= onfi_timings->tRC_min &&
- spec_timings->tREH_min <= onfi_timings->tREH_min &&
- spec_timings->tRHOH_min <= onfi_timings->tRHOH_min &&
- spec_timings->tRHW_min <= onfi_timings->tRHW_min &&
- spec_timings->tRLOH_min <= onfi_timings->tRLOH_min &&
- spec_timings->tRP_min <= onfi_timings->tRP_min &&
- spec_timings->tRR_min <= onfi_timings->tRR_min &&
- spec_timings->tWC_min <= onfi_timings->tWC_min &&
- spec_timings->tWH_min <= onfi_timings->tWH_min &&
- spec_timings->tWHR_min <= onfi_timings->tWHR_min &&
- spec_timings->tWP_min <= onfi_timings->tWP_min &&
- spec_timings->tWW_min <= onfi_timings->tWW_min)
- return mode;
- }
- return 0;
- }
- /**
- * onfi_find_closest_nvddr_mode - Derive the closest ONFI NVDDR timing mode
- * given a set of timings
- * @spec_timings: the timings to challenge
- */
- unsigned int
- onfi_find_closest_nvddr_mode(const struct nand_nvddr_timings *spec_timings)
- {
- const struct nand_nvddr_timings *onfi_timings;
- int mode;
- for (mode = ARRAY_SIZE(onfi_nvddr_timings) - 1; mode > 0; mode--) {
- onfi_timings = &onfi_nvddr_timings[mode].timings.nvddr;
- if (spec_timings->tCCS_min <= onfi_timings->tCCS_min &&
- spec_timings->tAC_min <= onfi_timings->tAC_min &&
- spec_timings->tADL_min <= onfi_timings->tADL_min &&
- spec_timings->tCAD_min <= onfi_timings->tCAD_min &&
- spec_timings->tCAH_min <= onfi_timings->tCAH_min &&
- spec_timings->tCALH_min <= onfi_timings->tCALH_min &&
- spec_timings->tCALS_min <= onfi_timings->tCALS_min &&
- spec_timings->tCAS_min <= onfi_timings->tCAS_min &&
- spec_timings->tCEH_min <= onfi_timings->tCEH_min &&
- spec_timings->tCH_min <= onfi_timings->tCH_min &&
- spec_timings->tCK_min <= onfi_timings->tCK_min &&
- spec_timings->tCS_min <= onfi_timings->tCS_min &&
- spec_timings->tDH_min <= onfi_timings->tDH_min &&
- spec_timings->tDQSCK_min <= onfi_timings->tDQSCK_min &&
- spec_timings->tDQSD_min <= onfi_timings->tDQSD_min &&
- spec_timings->tDS_min <= onfi_timings->tDS_min &&
- spec_timings->tDSC_min <= onfi_timings->tDSC_min &&
- spec_timings->tRHW_min <= onfi_timings->tRHW_min &&
- spec_timings->tRR_min <= onfi_timings->tRR_min &&
- spec_timings->tWHR_min <= onfi_timings->tWHR_min &&
- spec_timings->tWRCK_min <= onfi_timings->tWRCK_min &&
- spec_timings->tWW_min <= onfi_timings->tWW_min)
- return mode;
- }
- return 0;
- }
- /*
- * onfi_fill_sdr_interface_config - Initialize a SDR 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_sdr_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_sdr_timings)))
- return;
- *iface = onfi_sdr_timings[timing_mode];
- /*
- * Initialize timings that cannot be deduced from timing mode:
- * tPROG, tBERS, tR and tCCS.
- * These information are part of the ONFI parameter page.
- */
- if (onfi) {
- struct nand_sdr_timings *timings = &iface->timings.sdr;
- /* 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;
- }
- }
- /**
- * 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
- * @iface: The interface configuration to fill
- * @type: The interface type
- * @timing_mode: The ONFI timing mode
- */
- void onfi_fill_interface_config(struct nand_chip *chip,
- struct nand_interface_config *iface,
- enum nand_interface_type type,
- unsigned int timing_mode)
- {
- 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);
- }
|