1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2974647eaSBoris BREZILLON /* 3974647eaSBoris BREZILLON * Copyright (C) 2014 Free Electrons 4974647eaSBoris BREZILLON * 5974647eaSBoris BREZILLON * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> 6974647eaSBoris BREZILLON */ 7974647eaSBoris BREZILLON #include <linux/kernel.h> 8974647eaSBoris BREZILLON #include <linux/err.h> 9974647eaSBoris BREZILLON #include <linux/export.h> 10348d56a8SBoris Brezillon 11348d56a8SBoris Brezillon #include "internals.h" 12974647eaSBoris BREZILLON 136a943386SMiquel Raynal #define ONFI_DYN_TIMING_MAX U16_MAX 146a943386SMiquel Raynal 15b1dd3ca2SSascha Hauer static const struct nand_data_interface onfi_sdr_timings[] = { 16974647eaSBoris BREZILLON /* Mode 0 */ 17974647eaSBoris BREZILLON { 18b1dd3ca2SSascha Hauer .type = NAND_SDR_IFACE, 19b1dd3ca2SSascha Hauer .timings.sdr = { 20204e7ecdSBoris Brezillon .tCCS_min = 500000, 21204e7ecdSBoris Brezillon .tR_max = 200000000, 2274a332e7SBoris Brezillon .tADL_min = 400000, 23974647eaSBoris BREZILLON .tALH_min = 20000, 24974647eaSBoris BREZILLON .tALS_min = 50000, 25974647eaSBoris BREZILLON .tAR_min = 25000, 26974647eaSBoris BREZILLON .tCEA_max = 100000, 27974647eaSBoris BREZILLON .tCEH_min = 20000, 28974647eaSBoris BREZILLON .tCH_min = 20000, 29974647eaSBoris BREZILLON .tCHZ_max = 100000, 30974647eaSBoris BREZILLON .tCLH_min = 20000, 31974647eaSBoris BREZILLON .tCLR_min = 20000, 32974647eaSBoris BREZILLON .tCLS_min = 50000, 33974647eaSBoris BREZILLON .tCOH_min = 0, 34974647eaSBoris BREZILLON .tCS_min = 70000, 35974647eaSBoris BREZILLON .tDH_min = 20000, 36974647eaSBoris BREZILLON .tDS_min = 40000, 37974647eaSBoris BREZILLON .tFEAT_max = 1000000, 38974647eaSBoris BREZILLON .tIR_min = 10000, 39974647eaSBoris BREZILLON .tITC_max = 1000000, 40974647eaSBoris BREZILLON .tRC_min = 100000, 41974647eaSBoris BREZILLON .tREA_max = 40000, 42974647eaSBoris BREZILLON .tREH_min = 30000, 43974647eaSBoris BREZILLON .tRHOH_min = 0, 44974647eaSBoris BREZILLON .tRHW_min = 200000, 45974647eaSBoris BREZILLON .tRHZ_max = 200000, 46974647eaSBoris BREZILLON .tRLOH_min = 0, 47974647eaSBoris BREZILLON .tRP_min = 50000, 4857d419a4SBoris Brezillon .tRR_min = 40000, 49bd8898dbSGeert Uytterhoeven .tRST_max = 250000000000ULL, 50974647eaSBoris BREZILLON .tWB_max = 200000, 51974647eaSBoris BREZILLON .tWC_min = 100000, 52974647eaSBoris BREZILLON .tWH_min = 30000, 53974647eaSBoris BREZILLON .tWHR_min = 120000, 54974647eaSBoris BREZILLON .tWP_min = 50000, 55974647eaSBoris BREZILLON .tWW_min = 100000, 56974647eaSBoris BREZILLON }, 57b1dd3ca2SSascha Hauer }, 58974647eaSBoris BREZILLON /* Mode 1 */ 59974647eaSBoris BREZILLON { 60b1dd3ca2SSascha Hauer .type = NAND_SDR_IFACE, 61b1dd3ca2SSascha Hauer .timings.sdr = { 62204e7ecdSBoris Brezillon .tCCS_min = 500000, 63204e7ecdSBoris Brezillon .tR_max = 200000000, 6474a332e7SBoris Brezillon .tADL_min = 400000, 65974647eaSBoris BREZILLON .tALH_min = 10000, 66974647eaSBoris BREZILLON .tALS_min = 25000, 67974647eaSBoris BREZILLON .tAR_min = 10000, 68974647eaSBoris BREZILLON .tCEA_max = 45000, 69974647eaSBoris BREZILLON .tCEH_min = 20000, 70974647eaSBoris BREZILLON .tCH_min = 10000, 71974647eaSBoris BREZILLON .tCHZ_max = 50000, 72974647eaSBoris BREZILLON .tCLH_min = 10000, 73974647eaSBoris BREZILLON .tCLR_min = 10000, 74974647eaSBoris BREZILLON .tCLS_min = 25000, 75974647eaSBoris BREZILLON .tCOH_min = 15000, 76974647eaSBoris BREZILLON .tCS_min = 35000, 77974647eaSBoris BREZILLON .tDH_min = 10000, 78974647eaSBoris BREZILLON .tDS_min = 20000, 79974647eaSBoris BREZILLON .tFEAT_max = 1000000, 80974647eaSBoris BREZILLON .tIR_min = 0, 81974647eaSBoris BREZILLON .tITC_max = 1000000, 82974647eaSBoris BREZILLON .tRC_min = 50000, 83974647eaSBoris BREZILLON .tREA_max = 30000, 84974647eaSBoris BREZILLON .tREH_min = 15000, 85974647eaSBoris BREZILLON .tRHOH_min = 15000, 86974647eaSBoris BREZILLON .tRHW_min = 100000, 87974647eaSBoris BREZILLON .tRHZ_max = 100000, 88974647eaSBoris BREZILLON .tRLOH_min = 0, 89974647eaSBoris BREZILLON .tRP_min = 25000, 90974647eaSBoris BREZILLON .tRR_min = 20000, 91974647eaSBoris BREZILLON .tRST_max = 500000000, 92974647eaSBoris BREZILLON .tWB_max = 100000, 93974647eaSBoris BREZILLON .tWC_min = 45000, 94974647eaSBoris BREZILLON .tWH_min = 15000, 95974647eaSBoris BREZILLON .tWHR_min = 80000, 96974647eaSBoris BREZILLON .tWP_min = 25000, 97974647eaSBoris BREZILLON .tWW_min = 100000, 98974647eaSBoris BREZILLON }, 99b1dd3ca2SSascha Hauer }, 100974647eaSBoris BREZILLON /* Mode 2 */ 101974647eaSBoris BREZILLON { 102b1dd3ca2SSascha Hauer .type = NAND_SDR_IFACE, 103b1dd3ca2SSascha Hauer .timings.sdr = { 104204e7ecdSBoris Brezillon .tCCS_min = 500000, 105204e7ecdSBoris Brezillon .tR_max = 200000000, 10674a332e7SBoris Brezillon .tADL_min = 400000, 107974647eaSBoris BREZILLON .tALH_min = 10000, 108974647eaSBoris BREZILLON .tALS_min = 15000, 109974647eaSBoris BREZILLON .tAR_min = 10000, 110974647eaSBoris BREZILLON .tCEA_max = 30000, 111974647eaSBoris BREZILLON .tCEH_min = 20000, 112974647eaSBoris BREZILLON .tCH_min = 10000, 113974647eaSBoris BREZILLON .tCHZ_max = 50000, 114974647eaSBoris BREZILLON .tCLH_min = 10000, 115974647eaSBoris BREZILLON .tCLR_min = 10000, 116974647eaSBoris BREZILLON .tCLS_min = 15000, 117974647eaSBoris BREZILLON .tCOH_min = 15000, 118974647eaSBoris BREZILLON .tCS_min = 25000, 119974647eaSBoris BREZILLON .tDH_min = 5000, 120974647eaSBoris BREZILLON .tDS_min = 15000, 121974647eaSBoris BREZILLON .tFEAT_max = 1000000, 122974647eaSBoris BREZILLON .tIR_min = 0, 123974647eaSBoris BREZILLON .tITC_max = 1000000, 124974647eaSBoris BREZILLON .tRC_min = 35000, 125974647eaSBoris BREZILLON .tREA_max = 25000, 126974647eaSBoris BREZILLON .tREH_min = 15000, 127974647eaSBoris BREZILLON .tRHOH_min = 15000, 128974647eaSBoris BREZILLON .tRHW_min = 100000, 129974647eaSBoris BREZILLON .tRHZ_max = 100000, 130974647eaSBoris BREZILLON .tRLOH_min = 0, 131974647eaSBoris BREZILLON .tRR_min = 20000, 132974647eaSBoris BREZILLON .tRST_max = 500000000, 133974647eaSBoris BREZILLON .tWB_max = 100000, 134974647eaSBoris BREZILLON .tRP_min = 17000, 135974647eaSBoris BREZILLON .tWC_min = 35000, 136974647eaSBoris BREZILLON .tWH_min = 15000, 137974647eaSBoris BREZILLON .tWHR_min = 80000, 138974647eaSBoris BREZILLON .tWP_min = 17000, 139974647eaSBoris BREZILLON .tWW_min = 100000, 140974647eaSBoris BREZILLON }, 141b1dd3ca2SSascha Hauer }, 142974647eaSBoris BREZILLON /* Mode 3 */ 143974647eaSBoris BREZILLON { 144b1dd3ca2SSascha Hauer .type = NAND_SDR_IFACE, 145b1dd3ca2SSascha Hauer .timings.sdr = { 146204e7ecdSBoris Brezillon .tCCS_min = 500000, 147204e7ecdSBoris Brezillon .tR_max = 200000000, 14874a332e7SBoris Brezillon .tADL_min = 400000, 149974647eaSBoris BREZILLON .tALH_min = 5000, 150974647eaSBoris BREZILLON .tALS_min = 10000, 151974647eaSBoris BREZILLON .tAR_min = 10000, 152974647eaSBoris BREZILLON .tCEA_max = 25000, 153974647eaSBoris BREZILLON .tCEH_min = 20000, 154974647eaSBoris BREZILLON .tCH_min = 5000, 155974647eaSBoris BREZILLON .tCHZ_max = 50000, 156974647eaSBoris BREZILLON .tCLH_min = 5000, 157974647eaSBoris BREZILLON .tCLR_min = 10000, 158974647eaSBoris BREZILLON .tCLS_min = 10000, 159974647eaSBoris BREZILLON .tCOH_min = 15000, 160974647eaSBoris BREZILLON .tCS_min = 25000, 161974647eaSBoris BREZILLON .tDH_min = 5000, 162974647eaSBoris BREZILLON .tDS_min = 10000, 163974647eaSBoris BREZILLON .tFEAT_max = 1000000, 164974647eaSBoris BREZILLON .tIR_min = 0, 165974647eaSBoris BREZILLON .tITC_max = 1000000, 166974647eaSBoris BREZILLON .tRC_min = 30000, 167974647eaSBoris BREZILLON .tREA_max = 20000, 168974647eaSBoris BREZILLON .tREH_min = 10000, 169974647eaSBoris BREZILLON .tRHOH_min = 15000, 170974647eaSBoris BREZILLON .tRHW_min = 100000, 171974647eaSBoris BREZILLON .tRHZ_max = 100000, 172974647eaSBoris BREZILLON .tRLOH_min = 0, 173974647eaSBoris BREZILLON .tRP_min = 15000, 174974647eaSBoris BREZILLON .tRR_min = 20000, 175974647eaSBoris BREZILLON .tRST_max = 500000000, 176974647eaSBoris BREZILLON .tWB_max = 100000, 177974647eaSBoris BREZILLON .tWC_min = 30000, 178974647eaSBoris BREZILLON .tWH_min = 10000, 179974647eaSBoris BREZILLON .tWHR_min = 80000, 180974647eaSBoris BREZILLON .tWP_min = 15000, 181974647eaSBoris BREZILLON .tWW_min = 100000, 182974647eaSBoris BREZILLON }, 183b1dd3ca2SSascha Hauer }, 184974647eaSBoris BREZILLON /* Mode 4 */ 185974647eaSBoris BREZILLON { 186b1dd3ca2SSascha Hauer .type = NAND_SDR_IFACE, 187b1dd3ca2SSascha Hauer .timings.sdr = { 188204e7ecdSBoris Brezillon .tCCS_min = 500000, 189204e7ecdSBoris Brezillon .tR_max = 200000000, 19074a332e7SBoris Brezillon .tADL_min = 400000, 191974647eaSBoris BREZILLON .tALH_min = 5000, 192974647eaSBoris BREZILLON .tALS_min = 10000, 193974647eaSBoris BREZILLON .tAR_min = 10000, 194974647eaSBoris BREZILLON .tCEA_max = 25000, 195974647eaSBoris BREZILLON .tCEH_min = 20000, 196974647eaSBoris BREZILLON .tCH_min = 5000, 197974647eaSBoris BREZILLON .tCHZ_max = 30000, 198974647eaSBoris BREZILLON .tCLH_min = 5000, 199974647eaSBoris BREZILLON .tCLR_min = 10000, 200974647eaSBoris BREZILLON .tCLS_min = 10000, 201974647eaSBoris BREZILLON .tCOH_min = 15000, 202974647eaSBoris BREZILLON .tCS_min = 20000, 203974647eaSBoris BREZILLON .tDH_min = 5000, 204974647eaSBoris BREZILLON .tDS_min = 10000, 205974647eaSBoris BREZILLON .tFEAT_max = 1000000, 206974647eaSBoris BREZILLON .tIR_min = 0, 207974647eaSBoris BREZILLON .tITC_max = 1000000, 208974647eaSBoris BREZILLON .tRC_min = 25000, 209974647eaSBoris BREZILLON .tREA_max = 20000, 210974647eaSBoris BREZILLON .tREH_min = 10000, 211974647eaSBoris BREZILLON .tRHOH_min = 15000, 212974647eaSBoris BREZILLON .tRHW_min = 100000, 213974647eaSBoris BREZILLON .tRHZ_max = 100000, 214974647eaSBoris BREZILLON .tRLOH_min = 5000, 215974647eaSBoris BREZILLON .tRP_min = 12000, 216974647eaSBoris BREZILLON .tRR_min = 20000, 217974647eaSBoris BREZILLON .tRST_max = 500000000, 218974647eaSBoris BREZILLON .tWB_max = 100000, 219974647eaSBoris BREZILLON .tWC_min = 25000, 220974647eaSBoris BREZILLON .tWH_min = 10000, 221974647eaSBoris BREZILLON .tWHR_min = 80000, 222974647eaSBoris BREZILLON .tWP_min = 12000, 223974647eaSBoris BREZILLON .tWW_min = 100000, 224974647eaSBoris BREZILLON }, 225b1dd3ca2SSascha Hauer }, 226974647eaSBoris BREZILLON /* Mode 5 */ 227974647eaSBoris BREZILLON { 228b1dd3ca2SSascha Hauer .type = NAND_SDR_IFACE, 229b1dd3ca2SSascha Hauer .timings.sdr = { 230204e7ecdSBoris Brezillon .tCCS_min = 500000, 231204e7ecdSBoris Brezillon .tR_max = 200000000, 23274a332e7SBoris Brezillon .tADL_min = 400000, 233974647eaSBoris BREZILLON .tALH_min = 5000, 234974647eaSBoris BREZILLON .tALS_min = 10000, 235974647eaSBoris BREZILLON .tAR_min = 10000, 236974647eaSBoris BREZILLON .tCEA_max = 25000, 237974647eaSBoris BREZILLON .tCEH_min = 20000, 238974647eaSBoris BREZILLON .tCH_min = 5000, 239974647eaSBoris BREZILLON .tCHZ_max = 30000, 240974647eaSBoris BREZILLON .tCLH_min = 5000, 241974647eaSBoris BREZILLON .tCLR_min = 10000, 242974647eaSBoris BREZILLON .tCLS_min = 10000, 243974647eaSBoris BREZILLON .tCOH_min = 15000, 244974647eaSBoris BREZILLON .tCS_min = 15000, 245974647eaSBoris BREZILLON .tDH_min = 5000, 246974647eaSBoris BREZILLON .tDS_min = 7000, 247974647eaSBoris BREZILLON .tFEAT_max = 1000000, 248974647eaSBoris BREZILLON .tIR_min = 0, 249974647eaSBoris BREZILLON .tITC_max = 1000000, 250974647eaSBoris BREZILLON .tRC_min = 20000, 251974647eaSBoris BREZILLON .tREA_max = 16000, 252974647eaSBoris BREZILLON .tREH_min = 7000, 253974647eaSBoris BREZILLON .tRHOH_min = 15000, 254974647eaSBoris BREZILLON .tRHW_min = 100000, 255974647eaSBoris BREZILLON .tRHZ_max = 100000, 256974647eaSBoris BREZILLON .tRLOH_min = 5000, 257974647eaSBoris BREZILLON .tRP_min = 10000, 258974647eaSBoris BREZILLON .tRR_min = 20000, 259974647eaSBoris BREZILLON .tRST_max = 500000000, 260974647eaSBoris BREZILLON .tWB_max = 100000, 261974647eaSBoris BREZILLON .tWC_min = 20000, 262974647eaSBoris BREZILLON .tWH_min = 7000, 263974647eaSBoris BREZILLON .tWHR_min = 80000, 264974647eaSBoris BREZILLON .tWP_min = 10000, 265974647eaSBoris BREZILLON .tWW_min = 100000, 266974647eaSBoris BREZILLON }, 267b1dd3ca2SSascha Hauer }, 268974647eaSBoris BREZILLON }; 269974647eaSBoris BREZILLON 270974647eaSBoris BREZILLON /** 27117fa8044SMiquel Raynal * onfi_fill_data_interface - [NAND Interface] Initialize a data interface from 272b88730adSSascha Hauer * given ONFI mode 273b88730adSSascha Hauer * @mode: The ONFI timing mode 274b88730adSSascha Hauer */ 27517fa8044SMiquel Raynal int onfi_fill_data_interface(struct nand_chip *chip, 276b88730adSSascha Hauer enum nand_data_interface_type type, 277b88730adSSascha Hauer int timing_mode) 278b88730adSSascha Hauer { 27917fa8044SMiquel Raynal struct nand_data_interface *iface = &chip->data_interface; 2803d3fe3c0SMiquel Raynal struct onfi_params *onfi = chip->parameters.onfi; 28117fa8044SMiquel Raynal 282b88730adSSascha Hauer if (type != NAND_SDR_IFACE) 283b88730adSSascha Hauer return -EINVAL; 284b88730adSSascha Hauer 285b88730adSSascha Hauer if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings)) 286b88730adSSascha Hauer return -EINVAL; 287b88730adSSascha Hauer 288b88730adSSascha Hauer *iface = onfi_sdr_timings[timing_mode]; 289b88730adSSascha Hauer 290b88730adSSascha Hauer /* 291204e7ecdSBoris Brezillon * Initialize timings that cannot be deduced from timing mode: 2926a943386SMiquel Raynal * tPROG, tBERS, tR and tCCS. 293b88730adSSascha Hauer * These information are part of the ONFI parameter page. 294b88730adSSascha Hauer */ 2953d3fe3c0SMiquel Raynal if (onfi) { 296204e7ecdSBoris Brezillon struct nand_sdr_timings *timings = &iface->timings.sdr; 297204e7ecdSBoris Brezillon 298204e7ecdSBoris Brezillon /* microseconds -> picoseconds */ 2993d3fe3c0SMiquel Raynal timings->tPROG_max = 1000000ULL * onfi->tPROG; 3003d3fe3c0SMiquel Raynal timings->tBERS_max = 1000000ULL * onfi->tBERS; 3013d3fe3c0SMiquel Raynal timings->tR_max = 1000000ULL * onfi->tR; 302204e7ecdSBoris Brezillon 303204e7ecdSBoris Brezillon /* nanoseconds -> picoseconds */ 3043d3fe3c0SMiquel Raynal timings->tCCS_min = 1000UL * onfi->tCCS; 3056a943386SMiquel Raynal } else { 3066a943386SMiquel Raynal struct nand_sdr_timings *timings = &iface->timings.sdr; 3076a943386SMiquel Raynal /* 3086a943386SMiquel Raynal * For non-ONFI chips we use the highest possible value for 3096a943386SMiquel Raynal * tPROG and tBERS. tR and tCCS will take the default values 3106a943386SMiquel Raynal * precised in the ONFI specification for timing mode 0, 3116a943386SMiquel Raynal * respectively 200us and 500ns. 3126a943386SMiquel Raynal */ 3136a943386SMiquel Raynal 3146a943386SMiquel Raynal /* microseconds -> picoseconds */ 3156a943386SMiquel Raynal timings->tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX; 3166a943386SMiquel Raynal timings->tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX; 3176a943386SMiquel Raynal timings->tR_max = 1000000ULL * 200000000ULL; 3186a943386SMiquel Raynal 3196a943386SMiquel Raynal /* nanoseconds -> picoseconds */ 3206a943386SMiquel Raynal timings->tCCS_min = 1000UL * 500000; 321204e7ecdSBoris Brezillon } 322b88730adSSascha Hauer 323b88730adSSascha Hauer return 0; 324b88730adSSascha Hauer } 325