xref: /linux/drivers/mtd/nand/raw/nand_timings.c (revision d2912cb15bdda8ba4a5dd73396ad62641af2f520)
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