1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2014 Free Electrons |
4 | * |
5 | * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> |
6 | */ |
7 | #include <linux/kernel.h> |
8 | #include <linux/err.h> |
9 | #include <linux/export.h> |
10 | |
11 | #include "internals.h" |
12 | |
13 | #define ONFI_DYN_TIMING_MAX U16_MAX |
14 | |
15 | /* |
16 | * For non-ONFI chips we use the highest possible value for tPROG and tBERS. |
17 | * tR and tCCS will take the default values precised in the ONFI specification |
18 | * for timing mode 0, respectively 200us and 500ns. |
19 | * |
20 | * These four values are tweaked to be more accurate in the case of ONFI chips. |
21 | */ |
22 | static const struct nand_interface_config onfi_sdr_timings[] = { |
23 | /* Mode 0 */ |
24 | { |
25 | .type = NAND_SDR_IFACE, |
26 | .timings.mode = 0, |
27 | .timings.sdr = { |
28 | .tCCS_min = 500000, |
29 | .tR_max = 200000000, |
30 | .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
31 | .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
32 | .tADL_min = 400000, |
33 | .tALH_min = 20000, |
34 | .tALS_min = 50000, |
35 | .tAR_min = 25000, |
36 | .tCEA_max = 100000, |
37 | .tCEH_min = 20000, |
38 | .tCH_min = 20000, |
39 | .tCHZ_max = 100000, |
40 | .tCLH_min = 20000, |
41 | .tCLR_min = 20000, |
42 | .tCLS_min = 50000, |
43 | .tCOH_min = 0, |
44 | .tCS_min = 70000, |
45 | .tDH_min = 20000, |
46 | .tDS_min = 40000, |
47 | .tFEAT_max = 1000000, |
48 | .tIR_min = 10000, |
49 | .tITC_max = 1000000, |
50 | .tRC_min = 100000, |
51 | .tREA_max = 40000, |
52 | .tREH_min = 30000, |
53 | .tRHOH_min = 0, |
54 | .tRHW_min = 200000, |
55 | .tRHZ_max = 200000, |
56 | .tRLOH_min = 0, |
57 | .tRP_min = 50000, |
58 | .tRR_min = 40000, |
59 | .tRST_max = 250000000000ULL, |
60 | .tWB_max = 200000, |
61 | .tWC_min = 100000, |
62 | .tWH_min = 30000, |
63 | .tWHR_min = 120000, |
64 | .tWP_min = 50000, |
65 | .tWW_min = 100000, |
66 | }, |
67 | }, |
68 | /* Mode 1 */ |
69 | { |
70 | .type = NAND_SDR_IFACE, |
71 | .timings.mode = 1, |
72 | .timings.sdr = { |
73 | .tCCS_min = 500000, |
74 | .tR_max = 200000000, |
75 | .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
76 | .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
77 | .tADL_min = 400000, |
78 | .tALH_min = 10000, |
79 | .tALS_min = 25000, |
80 | .tAR_min = 10000, |
81 | .tCEA_max = 45000, |
82 | .tCEH_min = 20000, |
83 | .tCH_min = 10000, |
84 | .tCHZ_max = 50000, |
85 | .tCLH_min = 10000, |
86 | .tCLR_min = 10000, |
87 | .tCLS_min = 25000, |
88 | .tCOH_min = 15000, |
89 | .tCS_min = 35000, |
90 | .tDH_min = 10000, |
91 | .tDS_min = 20000, |
92 | .tFEAT_max = 1000000, |
93 | .tIR_min = 0, |
94 | .tITC_max = 1000000, |
95 | .tRC_min = 50000, |
96 | .tREA_max = 30000, |
97 | .tREH_min = 15000, |
98 | .tRHOH_min = 15000, |
99 | .tRHW_min = 100000, |
100 | .tRHZ_max = 100000, |
101 | .tRLOH_min = 0, |
102 | .tRP_min = 25000, |
103 | .tRR_min = 20000, |
104 | .tRST_max = 500000000, |
105 | .tWB_max = 100000, |
106 | .tWC_min = 45000, |
107 | .tWH_min = 15000, |
108 | .tWHR_min = 80000, |
109 | .tWP_min = 25000, |
110 | .tWW_min = 100000, |
111 | }, |
112 | }, |
113 | /* Mode 2 */ |
114 | { |
115 | .type = NAND_SDR_IFACE, |
116 | .timings.mode = 2, |
117 | .timings.sdr = { |
118 | .tCCS_min = 500000, |
119 | .tR_max = 200000000, |
120 | .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
121 | .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
122 | .tADL_min = 400000, |
123 | .tALH_min = 10000, |
124 | .tALS_min = 15000, |
125 | .tAR_min = 10000, |
126 | .tCEA_max = 30000, |
127 | .tCEH_min = 20000, |
128 | .tCH_min = 10000, |
129 | .tCHZ_max = 50000, |
130 | .tCLH_min = 10000, |
131 | .tCLR_min = 10000, |
132 | .tCLS_min = 15000, |
133 | .tCOH_min = 15000, |
134 | .tCS_min = 25000, |
135 | .tDH_min = 5000, |
136 | .tDS_min = 15000, |
137 | .tFEAT_max = 1000000, |
138 | .tIR_min = 0, |
139 | .tITC_max = 1000000, |
140 | .tRC_min = 35000, |
141 | .tREA_max = 25000, |
142 | .tREH_min = 15000, |
143 | .tRHOH_min = 15000, |
144 | .tRHW_min = 100000, |
145 | .tRHZ_max = 100000, |
146 | .tRLOH_min = 0, |
147 | .tRR_min = 20000, |
148 | .tRST_max = 500000000, |
149 | .tWB_max = 100000, |
150 | .tRP_min = 17000, |
151 | .tWC_min = 35000, |
152 | .tWH_min = 15000, |
153 | .tWHR_min = 80000, |
154 | .tWP_min = 17000, |
155 | .tWW_min = 100000, |
156 | }, |
157 | }, |
158 | /* Mode 3 */ |
159 | { |
160 | .type = NAND_SDR_IFACE, |
161 | .timings.mode = 3, |
162 | .timings.sdr = { |
163 | .tCCS_min = 500000, |
164 | .tR_max = 200000000, |
165 | .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
166 | .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
167 | .tADL_min = 400000, |
168 | .tALH_min = 5000, |
169 | .tALS_min = 10000, |
170 | .tAR_min = 10000, |
171 | .tCEA_max = 25000, |
172 | .tCEH_min = 20000, |
173 | .tCH_min = 5000, |
174 | .tCHZ_max = 50000, |
175 | .tCLH_min = 5000, |
176 | .tCLR_min = 10000, |
177 | .tCLS_min = 10000, |
178 | .tCOH_min = 15000, |
179 | .tCS_min = 25000, |
180 | .tDH_min = 5000, |
181 | .tDS_min = 10000, |
182 | .tFEAT_max = 1000000, |
183 | .tIR_min = 0, |
184 | .tITC_max = 1000000, |
185 | .tRC_min = 30000, |
186 | .tREA_max = 20000, |
187 | .tREH_min = 10000, |
188 | .tRHOH_min = 15000, |
189 | .tRHW_min = 100000, |
190 | .tRHZ_max = 100000, |
191 | .tRLOH_min = 0, |
192 | .tRP_min = 15000, |
193 | .tRR_min = 20000, |
194 | .tRST_max = 500000000, |
195 | .tWB_max = 100000, |
196 | .tWC_min = 30000, |
197 | .tWH_min = 10000, |
198 | .tWHR_min = 80000, |
199 | .tWP_min = 15000, |
200 | .tWW_min = 100000, |
201 | }, |
202 | }, |
203 | /* Mode 4 */ |
204 | { |
205 | .type = NAND_SDR_IFACE, |
206 | .timings.mode = 4, |
207 | .timings.sdr = { |
208 | .tCCS_min = 500000, |
209 | .tR_max = 200000000, |
210 | .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
211 | .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
212 | .tADL_min = 400000, |
213 | .tALH_min = 5000, |
214 | .tALS_min = 10000, |
215 | .tAR_min = 10000, |
216 | .tCEA_max = 25000, |
217 | .tCEH_min = 20000, |
218 | .tCH_min = 5000, |
219 | .tCHZ_max = 30000, |
220 | .tCLH_min = 5000, |
221 | .tCLR_min = 10000, |
222 | .tCLS_min = 10000, |
223 | .tCOH_min = 15000, |
224 | .tCS_min = 20000, |
225 | .tDH_min = 5000, |
226 | .tDS_min = 10000, |
227 | .tFEAT_max = 1000000, |
228 | .tIR_min = 0, |
229 | .tITC_max = 1000000, |
230 | .tRC_min = 25000, |
231 | .tREA_max = 20000, |
232 | .tREH_min = 10000, |
233 | .tRHOH_min = 15000, |
234 | .tRHW_min = 100000, |
235 | .tRHZ_max = 100000, |
236 | .tRLOH_min = 5000, |
237 | .tRP_min = 12000, |
238 | .tRR_min = 20000, |
239 | .tRST_max = 500000000, |
240 | .tWB_max = 100000, |
241 | .tWC_min = 25000, |
242 | .tWH_min = 10000, |
243 | .tWHR_min = 80000, |
244 | .tWP_min = 12000, |
245 | .tWW_min = 100000, |
246 | }, |
247 | }, |
248 | /* Mode 5 */ |
249 | { |
250 | .type = NAND_SDR_IFACE, |
251 | .timings.mode = 5, |
252 | .timings.sdr = { |
253 | .tCCS_min = 500000, |
254 | .tR_max = 200000000, |
255 | .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
256 | .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
257 | .tADL_min = 400000, |
258 | .tALH_min = 5000, |
259 | .tALS_min = 10000, |
260 | .tAR_min = 10000, |
261 | .tCEA_max = 25000, |
262 | .tCEH_min = 20000, |
263 | .tCH_min = 5000, |
264 | .tCHZ_max = 30000, |
265 | .tCLH_min = 5000, |
266 | .tCLR_min = 10000, |
267 | .tCLS_min = 10000, |
268 | .tCOH_min = 15000, |
269 | .tCS_min = 15000, |
270 | .tDH_min = 5000, |
271 | .tDS_min = 7000, |
272 | .tFEAT_max = 1000000, |
273 | .tIR_min = 0, |
274 | .tITC_max = 1000000, |
275 | .tRC_min = 20000, |
276 | .tREA_max = 16000, |
277 | .tREH_min = 7000, |
278 | .tRHOH_min = 15000, |
279 | .tRHW_min = 100000, |
280 | .tRHZ_max = 100000, |
281 | .tRLOH_min = 5000, |
282 | .tRP_min = 10000, |
283 | .tRR_min = 20000, |
284 | .tRST_max = 500000000, |
285 | .tWB_max = 100000, |
286 | .tWC_min = 20000, |
287 | .tWH_min = 7000, |
288 | .tWHR_min = 80000, |
289 | .tWP_min = 10000, |
290 | .tWW_min = 100000, |
291 | }, |
292 | }, |
293 | }; |
294 | |
295 | static const struct nand_interface_config onfi_nvddr_timings[] = { |
296 | /* Mode 0 */ |
297 | { |
298 | .type = NAND_NVDDR_IFACE, |
299 | .timings.mode = 0, |
300 | .timings.nvddr = { |
301 | .tCCS_min = 500000, |
302 | .tR_max = 200000000, |
303 | .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
304 | .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
305 | .tAC_min = 3000, |
306 | .tAC_max = 25000, |
307 | .tADL_min = 400000, |
308 | .tCAD_min = 45000, |
309 | .tCAH_min = 10000, |
310 | .tCALH_min = 10000, |
311 | .tCALS_min = 10000, |
312 | .tCAS_min = 10000, |
313 | .tCEH_min = 20000, |
314 | .tCH_min = 10000, |
315 | .tCK_min = 50000, |
316 | .tCS_min = 35000, |
317 | .tDH_min = 5000, |
318 | .tDQSCK_min = 3000, |
319 | .tDQSCK_max = 25000, |
320 | .tDQSD_min = 0, |
321 | .tDQSD_max = 18000, |
322 | .tDQSHZ_max = 20000, |
323 | .tDQSQ_max = 5000, |
324 | .tDS_min = 5000, |
325 | .tDSC_min = 50000, |
326 | .tFEAT_max = 1000000, |
327 | .tITC_max = 1000000, |
328 | .tQHS_max = 6000, |
329 | .tRHW_min = 100000, |
330 | .tRR_min = 20000, |
331 | .tRST_max = 500000000, |
332 | .tWB_max = 100000, |
333 | .tWHR_min = 80000, |
334 | .tWRCK_min = 20000, |
335 | .tWW_min = 100000, |
336 | }, |
337 | }, |
338 | /* Mode 1 */ |
339 | { |
340 | .type = NAND_NVDDR_IFACE, |
341 | .timings.mode = 1, |
342 | .timings.nvddr = { |
343 | .tCCS_min = 500000, |
344 | .tR_max = 200000000, |
345 | .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
346 | .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
347 | .tAC_min = 3000, |
348 | .tAC_max = 25000, |
349 | .tADL_min = 400000, |
350 | .tCAD_min = 45000, |
351 | .tCAH_min = 5000, |
352 | .tCALH_min = 5000, |
353 | .tCALS_min = 5000, |
354 | .tCAS_min = 5000, |
355 | .tCEH_min = 20000, |
356 | .tCH_min = 5000, |
357 | .tCK_min = 30000, |
358 | .tCS_min = 25000, |
359 | .tDH_min = 2500, |
360 | .tDQSCK_min = 3000, |
361 | .tDQSCK_max = 25000, |
362 | .tDQSD_min = 0, |
363 | .tDQSD_max = 18000, |
364 | .tDQSHZ_max = 20000, |
365 | .tDQSQ_max = 2500, |
366 | .tDS_min = 3000, |
367 | .tDSC_min = 30000, |
368 | .tFEAT_max = 1000000, |
369 | .tITC_max = 1000000, |
370 | .tQHS_max = 3000, |
371 | .tRHW_min = 100000, |
372 | .tRR_min = 20000, |
373 | .tRST_max = 500000000, |
374 | .tWB_max = 100000, |
375 | .tWHR_min = 80000, |
376 | .tWRCK_min = 20000, |
377 | .tWW_min = 100000, |
378 | }, |
379 | }, |
380 | /* Mode 2 */ |
381 | { |
382 | .type = NAND_NVDDR_IFACE, |
383 | .timings.mode = 2, |
384 | .timings.nvddr = { |
385 | .tCCS_min = 500000, |
386 | .tR_max = 200000000, |
387 | .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
388 | .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
389 | .tAC_min = 3000, |
390 | .tAC_max = 25000, |
391 | .tADL_min = 400000, |
392 | .tCAD_min = 45000, |
393 | .tCAH_min = 4000, |
394 | .tCALH_min = 4000, |
395 | .tCALS_min = 4000, |
396 | .tCAS_min = 4000, |
397 | .tCEH_min = 20000, |
398 | .tCH_min = 4000, |
399 | .tCK_min = 20000, |
400 | .tCS_min = 15000, |
401 | .tDH_min = 1700, |
402 | .tDQSCK_min = 3000, |
403 | .tDQSCK_max = 25000, |
404 | .tDQSD_min = 0, |
405 | .tDQSD_max = 18000, |
406 | .tDQSHZ_max = 20000, |
407 | .tDQSQ_max = 1700, |
408 | .tDS_min = 2000, |
409 | .tDSC_min = 20000, |
410 | .tFEAT_max = 1000000, |
411 | .tITC_max = 1000000, |
412 | .tQHS_max = 2000, |
413 | .tRHW_min = 100000, |
414 | .tRR_min = 20000, |
415 | .tRST_max = 500000000, |
416 | .tWB_max = 100000, |
417 | .tWHR_min = 80000, |
418 | .tWRCK_min = 20000, |
419 | .tWW_min = 100000, |
420 | }, |
421 | }, |
422 | /* Mode 3 */ |
423 | { |
424 | .type = NAND_NVDDR_IFACE, |
425 | .timings.mode = 3, |
426 | .timings.nvddr = { |
427 | .tCCS_min = 500000, |
428 | .tR_max = 200000000, |
429 | .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
430 | .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
431 | .tAC_min = 3000, |
432 | .tAC_max = 25000, |
433 | .tADL_min = 400000, |
434 | .tCAD_min = 45000, |
435 | .tCAH_min = 3000, |
436 | .tCALH_min = 3000, |
437 | .tCALS_min = 3000, |
438 | .tCAS_min = 3000, |
439 | .tCEH_min = 20000, |
440 | .tCH_min = 3000, |
441 | .tCK_min = 15000, |
442 | .tCS_min = 15000, |
443 | .tDH_min = 1300, |
444 | .tDQSCK_min = 3000, |
445 | .tDQSCK_max = 25000, |
446 | .tDQSD_min = 0, |
447 | .tDQSD_max = 18000, |
448 | .tDQSHZ_max = 20000, |
449 | .tDQSQ_max = 1300, |
450 | .tDS_min = 1500, |
451 | .tDSC_min = 15000, |
452 | .tFEAT_max = 1000000, |
453 | .tITC_max = 1000000, |
454 | .tQHS_max = 1500, |
455 | .tRHW_min = 100000, |
456 | .tRR_min = 20000, |
457 | .tRST_max = 500000000, |
458 | .tWB_max = 100000, |
459 | .tWHR_min = 80000, |
460 | .tWRCK_min = 20000, |
461 | .tWW_min = 100000, |
462 | }, |
463 | }, |
464 | /* Mode 4 */ |
465 | { |
466 | .type = NAND_NVDDR_IFACE, |
467 | .timings.mode = 4, |
468 | .timings.nvddr = { |
469 | .tCCS_min = 500000, |
470 | .tR_max = 200000000, |
471 | .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
472 | .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
473 | .tAC_min = 3000, |
474 | .tAC_max = 25000, |
475 | .tADL_min = 400000, |
476 | .tCAD_min = 45000, |
477 | .tCAH_min = 2500, |
478 | .tCALH_min = 2500, |
479 | .tCALS_min = 2500, |
480 | .tCAS_min = 2500, |
481 | .tCEH_min = 20000, |
482 | .tCH_min = 2500, |
483 | .tCK_min = 12000, |
484 | .tCS_min = 15000, |
485 | .tDH_min = 1100, |
486 | .tDQSCK_min = 3000, |
487 | .tDQSCK_max = 25000, |
488 | .tDQSD_min = 0, |
489 | .tDQSD_max = 18000, |
490 | .tDQSHZ_max = 20000, |
491 | .tDQSQ_max = 1000, |
492 | .tDS_min = 1100, |
493 | .tDSC_min = 12000, |
494 | .tFEAT_max = 1000000, |
495 | .tITC_max = 1000000, |
496 | .tQHS_max = 1200, |
497 | .tRHW_min = 100000, |
498 | .tRR_min = 20000, |
499 | .tRST_max = 500000000, |
500 | .tWB_max = 100000, |
501 | .tWHR_min = 80000, |
502 | .tWRCK_min = 20000, |
503 | .tWW_min = 100000, |
504 | }, |
505 | }, |
506 | /* Mode 5 */ |
507 | { |
508 | .type = NAND_NVDDR_IFACE, |
509 | .timings.mode = 5, |
510 | .timings.nvddr = { |
511 | .tCCS_min = 500000, |
512 | .tR_max = 200000000, |
513 | .tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
514 | .tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX, |
515 | .tAC_min = 3000, |
516 | .tAC_max = 25000, |
517 | .tADL_min = 400000, |
518 | .tCAD_min = 45000, |
519 | .tCAH_min = 2000, |
520 | .tCALH_min = 2000, |
521 | .tCALS_min = 2000, |
522 | .tCAS_min = 2000, |
523 | .tCEH_min = 20000, |
524 | .tCH_min = 2000, |
525 | .tCK_min = 10000, |
526 | .tCS_min = 15000, |
527 | .tDH_min = 900, |
528 | .tDQSCK_min = 3000, |
529 | .tDQSCK_max = 25000, |
530 | .tDQSD_min = 0, |
531 | .tDQSD_max = 18000, |
532 | .tDQSHZ_max = 20000, |
533 | .tDQSQ_max = 850, |
534 | .tDS_min = 900, |
535 | .tDSC_min = 10000, |
536 | .tFEAT_max = 1000000, |
537 | .tITC_max = 1000000, |
538 | .tQHS_max = 1000, |
539 | .tRHW_min = 100000, |
540 | .tRR_min = 20000, |
541 | .tRST_max = 500000000, |
542 | .tWB_max = 100000, |
543 | .tWHR_min = 80000, |
544 | .tWRCK_min = 20000, |
545 | .tWW_min = 100000, |
546 | }, |
547 | }, |
548 | }; |
549 | |
550 | /* All NAND chips share the same reset data interface: SDR mode 0 */ |
551 | const struct nand_interface_config *nand_get_reset_interface_config(void) |
552 | { |
553 | return &onfi_sdr_timings[0]; |
554 | } |
555 | |
556 | /** |
557 | * onfi_find_closest_sdr_mode - Derive the closest ONFI SDR timing mode given a |
558 | * set of timings |
559 | * @spec_timings: the timings to challenge |
560 | */ |
561 | unsigned int |
562 | onfi_find_closest_sdr_mode(const struct nand_sdr_timings *spec_timings) |
563 | { |
564 | const struct nand_sdr_timings *onfi_timings; |
565 | int mode; |
566 | |
567 | for (mode = ARRAY_SIZE(onfi_sdr_timings) - 1; mode > 0; mode--) { |
568 | onfi_timings = &onfi_sdr_timings[mode].timings.sdr; |
569 | |
570 | if (spec_timings->tCCS_min <= onfi_timings->tCCS_min && |
571 | spec_timings->tADL_min <= onfi_timings->tADL_min && |
572 | spec_timings->tALH_min <= onfi_timings->tALH_min && |
573 | spec_timings->tALS_min <= onfi_timings->tALS_min && |
574 | spec_timings->tAR_min <= onfi_timings->tAR_min && |
575 | spec_timings->tCEH_min <= onfi_timings->tCEH_min && |
576 | spec_timings->tCH_min <= onfi_timings->tCH_min && |
577 | spec_timings->tCLH_min <= onfi_timings->tCLH_min && |
578 | spec_timings->tCLR_min <= onfi_timings->tCLR_min && |
579 | spec_timings->tCLS_min <= onfi_timings->tCLS_min && |
580 | spec_timings->tCOH_min <= onfi_timings->tCOH_min && |
581 | spec_timings->tCS_min <= onfi_timings->tCS_min && |
582 | spec_timings->tDH_min <= onfi_timings->tDH_min && |
583 | spec_timings->tDS_min <= onfi_timings->tDS_min && |
584 | spec_timings->tIR_min <= onfi_timings->tIR_min && |
585 | spec_timings->tRC_min <= onfi_timings->tRC_min && |
586 | spec_timings->tREH_min <= onfi_timings->tREH_min && |
587 | spec_timings->tRHOH_min <= onfi_timings->tRHOH_min && |
588 | spec_timings->tRHW_min <= onfi_timings->tRHW_min && |
589 | spec_timings->tRLOH_min <= onfi_timings->tRLOH_min && |
590 | spec_timings->tRP_min <= onfi_timings->tRP_min && |
591 | spec_timings->tRR_min <= onfi_timings->tRR_min && |
592 | spec_timings->tWC_min <= onfi_timings->tWC_min && |
593 | spec_timings->tWH_min <= onfi_timings->tWH_min && |
594 | spec_timings->tWHR_min <= onfi_timings->tWHR_min && |
595 | spec_timings->tWP_min <= onfi_timings->tWP_min && |
596 | spec_timings->tWW_min <= onfi_timings->tWW_min) |
597 | return mode; |
598 | } |
599 | |
600 | return 0; |
601 | } |
602 | |
603 | /** |
604 | * onfi_find_closest_nvddr_mode - Derive the closest ONFI NVDDR timing mode |
605 | * given a set of timings |
606 | * @spec_timings: the timings to challenge |
607 | */ |
608 | unsigned int |
609 | onfi_find_closest_nvddr_mode(const struct nand_nvddr_timings *spec_timings) |
610 | { |
611 | const struct nand_nvddr_timings *onfi_timings; |
612 | int mode; |
613 | |
614 | for (mode = ARRAY_SIZE(onfi_nvddr_timings) - 1; mode > 0; mode--) { |
615 | onfi_timings = &onfi_nvddr_timings[mode].timings.nvddr; |
616 | |
617 | if (spec_timings->tCCS_min <= onfi_timings->tCCS_min && |
618 | spec_timings->tAC_min <= onfi_timings->tAC_min && |
619 | spec_timings->tADL_min <= onfi_timings->tADL_min && |
620 | spec_timings->tCAD_min <= onfi_timings->tCAD_min && |
621 | spec_timings->tCAH_min <= onfi_timings->tCAH_min && |
622 | spec_timings->tCALH_min <= onfi_timings->tCALH_min && |
623 | spec_timings->tCALS_min <= onfi_timings->tCALS_min && |
624 | spec_timings->tCAS_min <= onfi_timings->tCAS_min && |
625 | spec_timings->tCEH_min <= onfi_timings->tCEH_min && |
626 | spec_timings->tCH_min <= onfi_timings->tCH_min && |
627 | spec_timings->tCK_min <= onfi_timings->tCK_min && |
628 | spec_timings->tCS_min <= onfi_timings->tCS_min && |
629 | spec_timings->tDH_min <= onfi_timings->tDH_min && |
630 | spec_timings->tDQSCK_min <= onfi_timings->tDQSCK_min && |
631 | spec_timings->tDQSD_min <= onfi_timings->tDQSD_min && |
632 | spec_timings->tDS_min <= onfi_timings->tDS_min && |
633 | spec_timings->tDSC_min <= onfi_timings->tDSC_min && |
634 | spec_timings->tRHW_min <= onfi_timings->tRHW_min && |
635 | spec_timings->tRR_min <= onfi_timings->tRR_min && |
636 | spec_timings->tWHR_min <= onfi_timings->tWHR_min && |
637 | spec_timings->tWRCK_min <= onfi_timings->tWRCK_min && |
638 | spec_timings->tWW_min <= onfi_timings->tWW_min) |
639 | return mode; |
640 | } |
641 | |
642 | return 0; |
643 | } |
644 | |
645 | /* |
646 | * onfi_fill_sdr_interface_config - Initialize a SDR interface config from a |
647 | * given ONFI mode |
648 | * @chip: The NAND chip |
649 | * @iface: The interface configuration to fill |
650 | * @timing_mode: The ONFI timing mode |
651 | */ |
652 | static void onfi_fill_sdr_interface_config(struct nand_chip *chip, |
653 | struct nand_interface_config *iface, |
654 | unsigned int timing_mode) |
655 | { |
656 | struct onfi_params *onfi = chip->parameters.onfi; |
657 | |
658 | if (WARN_ON(timing_mode >= ARRAY_SIZE(onfi_sdr_timings))) |
659 | return; |
660 | |
661 | *iface = onfi_sdr_timings[timing_mode]; |
662 | |
663 | /* |
664 | * Initialize timings that cannot be deduced from timing mode: |
665 | * tPROG, tBERS, tR and tCCS. |
666 | * These information are part of the ONFI parameter page. |
667 | */ |
668 | if (onfi) { |
669 | struct nand_sdr_timings *timings = &iface->timings.sdr; |
670 | |
671 | /* microseconds -> picoseconds */ |
672 | timings->tPROG_max = 1000000ULL * onfi->tPROG; |
673 | timings->tBERS_max = 1000000ULL * onfi->tBERS; |
674 | timings->tR_max = 1000000ULL * onfi->tR; |
675 | |
676 | /* nanoseconds -> picoseconds */ |
677 | timings->tCCS_min = 1000UL * onfi->tCCS; |
678 | } |
679 | } |
680 | |
681 | /** |
682 | * onfi_fill_nvddr_interface_config - Initialize a NVDDR interface config from a |
683 | * given ONFI mode |
684 | * @chip: The NAND chip |
685 | * @iface: The interface configuration to fill |
686 | * @timing_mode: The ONFI timing mode |
687 | */ |
688 | static void onfi_fill_nvddr_interface_config(struct nand_chip *chip, |
689 | struct nand_interface_config *iface, |
690 | unsigned int timing_mode) |
691 | { |
692 | struct onfi_params *onfi = chip->parameters.onfi; |
693 | |
694 | if (WARN_ON(timing_mode >= ARRAY_SIZE(onfi_nvddr_timings))) |
695 | return; |
696 | |
697 | *iface = onfi_nvddr_timings[timing_mode]; |
698 | |
699 | /* |
700 | * Initialize timings that cannot be deduced from timing mode: |
701 | * tPROG, tBERS, tR, tCCS and tCAD. |
702 | * These information are part of the ONFI parameter page. |
703 | */ |
704 | if (onfi) { |
705 | struct nand_nvddr_timings *timings = &iface->timings.nvddr; |
706 | |
707 | /* microseconds -> picoseconds */ |
708 | timings->tPROG_max = 1000000ULL * onfi->tPROG; |
709 | timings->tBERS_max = 1000000ULL * onfi->tBERS; |
710 | timings->tR_max = 1000000ULL * onfi->tR; |
711 | |
712 | /* nanoseconds -> picoseconds */ |
713 | timings->tCCS_min = 1000UL * onfi->tCCS; |
714 | |
715 | if (onfi->fast_tCAD) |
716 | timings->tCAD_min = 25000; |
717 | } |
718 | } |
719 | |
720 | /** |
721 | * onfi_fill_interface_config - Initialize an interface config from a given |
722 | * ONFI mode |
723 | * @chip: The NAND chip |
724 | * @iface: The interface configuration to fill |
725 | * @type: The interface type |
726 | * @timing_mode: The ONFI timing mode |
727 | */ |
728 | void onfi_fill_interface_config(struct nand_chip *chip, |
729 | struct nand_interface_config *iface, |
730 | enum nand_interface_type type, |
731 | unsigned int timing_mode) |
732 | { |
733 | if (type == NAND_SDR_IFACE) |
734 | return onfi_fill_sdr_interface_config(chip, iface, timing_mode); |
735 | else |
736 | return onfi_fill_nvddr_interface_config(chip, iface, timing_mode); |
737 | } |
738 | |