blob: e6aa79039131ce1e0c4c172dcaae0a8f9f87b929 [file] [log] [blame]
Scott Wood3ea94ed2015-06-26 19:03:26 -05001/*
2 * Copyright (C) 2014 Free Electrons
3 *
4 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 */
11#include <common.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070012#include <linux/err.h>
Scott Wood3ea94ed2015-06-26 19:03:26 -050013#include <linux/kernel.h>
Masahiro Yamada2b7a8732017-11-30 13:45:24 +090014#include <linux/mtd/rawnand.h>
Scott Wood3ea94ed2015-06-26 19:03:26 -050015
Sascha Hauer0919fd32017-11-22 02:38:17 +090016static const struct nand_data_interface onfi_sdr_timings[] = {
Scott Wood3ea94ed2015-06-26 19:03:26 -050017 /* Mode 0 */
18 {
Sascha Hauer0919fd32017-11-22 02:38:17 +090019 .type = NAND_SDR_IFACE,
20 .timings.sdr = {
Boris Brezillona947e642017-11-22 02:38:21 +090021 .tCCS_min = 500000,
22 .tR_max = 200000000,
Sascha Hauer0919fd32017-11-22 02:38:17 +090023 .tADL_min = 400000,
24 .tALH_min = 20000,
25 .tALS_min = 50000,
26 .tAR_min = 25000,
27 .tCEA_max = 100000,
28 .tCEH_min = 20000,
29 .tCH_min = 20000,
30 .tCHZ_max = 100000,
31 .tCLH_min = 20000,
32 .tCLR_min = 20000,
33 .tCLS_min = 50000,
34 .tCOH_min = 0,
35 .tCS_min = 70000,
36 .tDH_min = 20000,
37 .tDS_min = 40000,
38 .tFEAT_max = 1000000,
39 .tIR_min = 10000,
40 .tITC_max = 1000000,
41 .tRC_min = 100000,
42 .tREA_max = 40000,
43 .tREH_min = 30000,
44 .tRHOH_min = 0,
45 .tRHW_min = 200000,
46 .tRHZ_max = 200000,
47 .tRLOH_min = 0,
48 .tRP_min = 50000,
49 .tRR_min = 40000,
50 .tRST_max = 250000000000ULL,
51 .tWB_max = 200000,
52 .tWC_min = 100000,
53 .tWH_min = 30000,
54 .tWHR_min = 120000,
55 .tWP_min = 50000,
56 .tWW_min = 100000,
57 },
Scott Wood3ea94ed2015-06-26 19:03:26 -050058 },
59 /* Mode 1 */
60 {
Sascha Hauer0919fd32017-11-22 02:38:17 +090061 .type = NAND_SDR_IFACE,
62 .timings.sdr = {
Boris Brezillona947e642017-11-22 02:38:21 +090063 .tCCS_min = 500000,
64 .tR_max = 200000000,
Sascha Hauer0919fd32017-11-22 02:38:17 +090065 .tADL_min = 400000,
66 .tALH_min = 10000,
67 .tALS_min = 25000,
68 .tAR_min = 10000,
69 .tCEA_max = 45000,
70 .tCEH_min = 20000,
71 .tCH_min = 10000,
72 .tCHZ_max = 50000,
73 .tCLH_min = 10000,
74 .tCLR_min = 10000,
75 .tCLS_min = 25000,
76 .tCOH_min = 15000,
77 .tCS_min = 35000,
78 .tDH_min = 10000,
79 .tDS_min = 20000,
80 .tFEAT_max = 1000000,
81 .tIR_min = 0,
82 .tITC_max = 1000000,
83 .tRC_min = 50000,
84 .tREA_max = 30000,
85 .tREH_min = 15000,
86 .tRHOH_min = 15000,
87 .tRHW_min = 100000,
88 .tRHZ_max = 100000,
89 .tRLOH_min = 0,
90 .tRP_min = 25000,
91 .tRR_min = 20000,
92 .tRST_max = 500000000,
93 .tWB_max = 100000,
94 .tWC_min = 45000,
95 .tWH_min = 15000,
96 .tWHR_min = 80000,
97 .tWP_min = 25000,
98 .tWW_min = 100000,
99 },
Scott Wood3ea94ed2015-06-26 19:03:26 -0500100 },
101 /* Mode 2 */
102 {
Sascha Hauer0919fd32017-11-22 02:38:17 +0900103 .type = NAND_SDR_IFACE,
104 .timings.sdr = {
Boris Brezillona947e642017-11-22 02:38:21 +0900105 .tCCS_min = 500000,
106 .tR_max = 200000000,
Sascha Hauer0919fd32017-11-22 02:38:17 +0900107 .tADL_min = 400000,
108 .tALH_min = 10000,
109 .tALS_min = 15000,
110 .tAR_min = 10000,
111 .tCEA_max = 30000,
112 .tCEH_min = 20000,
113 .tCH_min = 10000,
114 .tCHZ_max = 50000,
115 .tCLH_min = 10000,
116 .tCLR_min = 10000,
117 .tCLS_min = 15000,
118 .tCOH_min = 15000,
119 .tCS_min = 25000,
120 .tDH_min = 5000,
121 .tDS_min = 15000,
122 .tFEAT_max = 1000000,
123 .tIR_min = 0,
124 .tITC_max = 1000000,
125 .tRC_min = 35000,
126 .tREA_max = 25000,
127 .tREH_min = 15000,
128 .tRHOH_min = 15000,
129 .tRHW_min = 100000,
130 .tRHZ_max = 100000,
131 .tRLOH_min = 0,
132 .tRR_min = 20000,
133 .tRST_max = 500000000,
134 .tWB_max = 100000,
135 .tRP_min = 17000,
136 .tWC_min = 35000,
137 .tWH_min = 15000,
138 .tWHR_min = 80000,
139 .tWP_min = 17000,
140 .tWW_min = 100000,
141 },
Scott Wood3ea94ed2015-06-26 19:03:26 -0500142 },
143 /* Mode 3 */
144 {
Sascha Hauer0919fd32017-11-22 02:38:17 +0900145 .type = NAND_SDR_IFACE,
146 .timings.sdr = {
Boris Brezillona947e642017-11-22 02:38:21 +0900147 .tCCS_min = 500000,
148 .tR_max = 200000000,
Sascha Hauer0919fd32017-11-22 02:38:17 +0900149 .tADL_min = 400000,
150 .tALH_min = 5000,
151 .tALS_min = 10000,
152 .tAR_min = 10000,
153 .tCEA_max = 25000,
154 .tCEH_min = 20000,
155 .tCH_min = 5000,
156 .tCHZ_max = 50000,
157 .tCLH_min = 5000,
158 .tCLR_min = 10000,
159 .tCLS_min = 10000,
160 .tCOH_min = 15000,
161 .tCS_min = 25000,
162 .tDH_min = 5000,
163 .tDS_min = 10000,
164 .tFEAT_max = 1000000,
165 .tIR_min = 0,
166 .tITC_max = 1000000,
167 .tRC_min = 30000,
168 .tREA_max = 20000,
169 .tREH_min = 10000,
170 .tRHOH_min = 15000,
171 .tRHW_min = 100000,
172 .tRHZ_max = 100000,
173 .tRLOH_min = 0,
174 .tRP_min = 15000,
175 .tRR_min = 20000,
176 .tRST_max = 500000000,
177 .tWB_max = 100000,
178 .tWC_min = 30000,
179 .tWH_min = 10000,
180 .tWHR_min = 80000,
181 .tWP_min = 15000,
182 .tWW_min = 100000,
183 },
Scott Wood3ea94ed2015-06-26 19:03:26 -0500184 },
185 /* Mode 4 */
186 {
Sascha Hauer0919fd32017-11-22 02:38:17 +0900187 .type = NAND_SDR_IFACE,
188 .timings.sdr = {
Boris Brezillona947e642017-11-22 02:38:21 +0900189 .tCCS_min = 500000,
190 .tR_max = 200000000,
Sascha Hauer0919fd32017-11-22 02:38:17 +0900191 .tADL_min = 400000,
192 .tALH_min = 5000,
193 .tALS_min = 10000,
194 .tAR_min = 10000,
195 .tCEA_max = 25000,
196 .tCEH_min = 20000,
197 .tCH_min = 5000,
198 .tCHZ_max = 30000,
199 .tCLH_min = 5000,
200 .tCLR_min = 10000,
201 .tCLS_min = 10000,
202 .tCOH_min = 15000,
203 .tCS_min = 20000,
204 .tDH_min = 5000,
205 .tDS_min = 10000,
206 .tFEAT_max = 1000000,
207 .tIR_min = 0,
208 .tITC_max = 1000000,
209 .tRC_min = 25000,
210 .tREA_max = 20000,
211 .tREH_min = 10000,
212 .tRHOH_min = 15000,
213 .tRHW_min = 100000,
214 .tRHZ_max = 100000,
215 .tRLOH_min = 5000,
216 .tRP_min = 12000,
217 .tRR_min = 20000,
218 .tRST_max = 500000000,
219 .tWB_max = 100000,
220 .tWC_min = 25000,
221 .tWH_min = 10000,
222 .tWHR_min = 80000,
223 .tWP_min = 12000,
224 .tWW_min = 100000,
225 },
Scott Wood3ea94ed2015-06-26 19:03:26 -0500226 },
227 /* Mode 5 */
228 {
Sascha Hauer0919fd32017-11-22 02:38:17 +0900229 .type = NAND_SDR_IFACE,
230 .timings.sdr = {
Boris Brezillona947e642017-11-22 02:38:21 +0900231 .tCCS_min = 500000,
232 .tR_max = 200000000,
Sascha Hauer0919fd32017-11-22 02:38:17 +0900233 .tADL_min = 400000,
234 .tALH_min = 5000,
235 .tALS_min = 10000,
236 .tAR_min = 10000,
237 .tCEA_max = 25000,
238 .tCEH_min = 20000,
239 .tCH_min = 5000,
240 .tCHZ_max = 30000,
241 .tCLH_min = 5000,
242 .tCLR_min = 10000,
243 .tCLS_min = 10000,
244 .tCOH_min = 15000,
245 .tCS_min = 15000,
246 .tDH_min = 5000,
247 .tDS_min = 7000,
248 .tFEAT_max = 1000000,
249 .tIR_min = 0,
250 .tITC_max = 1000000,
251 .tRC_min = 20000,
252 .tREA_max = 16000,
253 .tREH_min = 7000,
254 .tRHOH_min = 15000,
255 .tRHW_min = 100000,
256 .tRHZ_max = 100000,
257 .tRLOH_min = 5000,
258 .tRP_min = 10000,
259 .tRR_min = 20000,
260 .tRST_max = 500000000,
261 .tWB_max = 100000,
262 .tWC_min = 20000,
263 .tWH_min = 7000,
264 .tWHR_min = 80000,
265 .tWP_min = 10000,
266 .tWW_min = 100000,
267 },
Scott Wood3ea94ed2015-06-26 19:03:26 -0500268 },
269};
270
271/**
272 * onfi_async_timing_mode_to_sdr_timings - [NAND Interface] Retrieve NAND
273 * timings according to the given ONFI timing mode
274 * @mode: ONFI timing mode
275 */
276const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
277{
278 if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings))
279 return ERR_PTR(-EINVAL);
280
Sascha Hauer0919fd32017-11-22 02:38:17 +0900281 return &onfi_sdr_timings[mode].timings.sdr;
Scott Wood3ea94ed2015-06-26 19:03:26 -0500282}
283EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
Sascha Hauer0919fd32017-11-22 02:38:17 +0900284
285/**
286 * onfi_init_data_interface - [NAND Interface] Initialize a data interface from
287 * given ONFI mode
288 * @iface: The data interface to be initialized
289 * @mode: The ONFI timing mode
290 */
291int onfi_init_data_interface(struct nand_chip *chip,
292 struct nand_data_interface *iface,
293 enum nand_data_interface_type type,
294 int timing_mode)
295{
296 if (type != NAND_SDR_IFACE)
297 return -EINVAL;
298
299 if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings))
300 return -EINVAL;
301
302 *iface = onfi_sdr_timings[timing_mode];
303
304 /*
Boris Brezillona947e642017-11-22 02:38:21 +0900305 * Initialize timings that cannot be deduced from timing mode:
Sascha Hauer0919fd32017-11-22 02:38:17 +0900306 * tR, tPROG, tCCS, ...
307 * These information are part of the ONFI parameter page.
308 */
Boris Brezillona947e642017-11-22 02:38:21 +0900309 if (chip->onfi_version) {
310 struct nand_onfi_params *params = &chip->onfi_params;
311 struct nand_sdr_timings *timings = &iface->timings.sdr;
312
313 /* microseconds -> picoseconds */
314 timings->tPROG_max = 1000000ULL * le16_to_cpu(params->t_prog);
315 timings->tBERS_max = 1000000ULL * le16_to_cpu(params->t_bers);
316 timings->tR_max = 1000000ULL * le16_to_cpu(params->t_r);
317
318 /* nanoseconds -> picoseconds */
319 timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs);
320 }
Sascha Hauer0919fd32017-11-22 02:38:17 +0900321
322 return 0;
323}
324EXPORT_SYMBOL(onfi_init_data_interface);
Sascha Hauere8142e22017-11-22 02:38:18 +0900325
326/**
327 * nand_get_default_data_interface - [NAND Interface] Retrieve NAND
328 * data interface for mode 0. This is used as default timing after
329 * reset.
330 */
331const struct nand_data_interface *nand_get_default_data_interface(void)
332{
333 return &onfi_sdr_timings[0];
334}
335EXPORT_SYMBOL(nand_get_default_data_interface);