blob: 9bb599106a31486b223b0ff8d04b97b7565b6c4e [file] [log] [blame]
Boris BREZILLON974647e2014-07-11 09:49:42 +02001/*
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 <linux/kernel.h>
12#include <linux/err.h>
13#include <linux/export.h>
Boris Brezillond4092d72017-08-04 17:29:10 +020014#include <linux/mtd/rawnand.h>
Boris BREZILLON974647e2014-07-11 09:49:42 +020015
Miquel Raynal6a943382018-07-14 12:23:54 +020016#define ONFI_DYN_TIMING_MAX U16_MAX
17
Sascha Hauerb1dd3ca2016-09-15 10:32:47 +020018static const struct nand_data_interface onfi_sdr_timings[] = {
Boris BREZILLON974647e2014-07-11 09:49:42 +020019 /* Mode 0 */
20 {
Sascha Hauerb1dd3ca2016-09-15 10:32:47 +020021 .type = NAND_SDR_IFACE,
22 .timings.sdr = {
Boris Brezillon204e7ec2016-10-01 10:24:02 +020023 .tCCS_min = 500000,
24 .tR_max = 200000000,
Sascha Hauerb1dd3ca2016-09-15 10:32:47 +020025 .tADL_min = 400000,
26 .tALH_min = 20000,
27 .tALS_min = 50000,
28 .tAR_min = 25000,
29 .tCEA_max = 100000,
30 .tCEH_min = 20000,
31 .tCH_min = 20000,
32 .tCHZ_max = 100000,
33 .tCLH_min = 20000,
34 .tCLR_min = 20000,
35 .tCLS_min = 50000,
36 .tCOH_min = 0,
37 .tCS_min = 70000,
38 .tDH_min = 20000,
39 .tDS_min = 40000,
40 .tFEAT_max = 1000000,
41 .tIR_min = 10000,
42 .tITC_max = 1000000,
43 .tRC_min = 100000,
44 .tREA_max = 40000,
45 .tREH_min = 30000,
46 .tRHOH_min = 0,
47 .tRHW_min = 200000,
48 .tRHZ_max = 200000,
49 .tRLOH_min = 0,
50 .tRP_min = 50000,
51 .tRR_min = 40000,
52 .tRST_max = 250000000000ULL,
53 .tWB_max = 200000,
54 .tWC_min = 100000,
55 .tWH_min = 30000,
56 .tWHR_min = 120000,
57 .tWP_min = 50000,
58 .tWW_min = 100000,
59 },
Boris BREZILLON974647e2014-07-11 09:49:42 +020060 },
61 /* Mode 1 */
62 {
Sascha Hauerb1dd3ca2016-09-15 10:32:47 +020063 .type = NAND_SDR_IFACE,
64 .timings.sdr = {
Boris Brezillon204e7ec2016-10-01 10:24:02 +020065 .tCCS_min = 500000,
66 .tR_max = 200000000,
Sascha Hauerb1dd3ca2016-09-15 10:32:47 +020067 .tADL_min = 400000,
68 .tALH_min = 10000,
69 .tALS_min = 25000,
70 .tAR_min = 10000,
71 .tCEA_max = 45000,
72 .tCEH_min = 20000,
73 .tCH_min = 10000,
74 .tCHZ_max = 50000,
75 .tCLH_min = 10000,
76 .tCLR_min = 10000,
77 .tCLS_min = 25000,
78 .tCOH_min = 15000,
79 .tCS_min = 35000,
80 .tDH_min = 10000,
81 .tDS_min = 20000,
82 .tFEAT_max = 1000000,
83 .tIR_min = 0,
84 .tITC_max = 1000000,
85 .tRC_min = 50000,
86 .tREA_max = 30000,
87 .tREH_min = 15000,
88 .tRHOH_min = 15000,
89 .tRHW_min = 100000,
90 .tRHZ_max = 100000,
91 .tRLOH_min = 0,
92 .tRP_min = 25000,
93 .tRR_min = 20000,
94 .tRST_max = 500000000,
95 .tWB_max = 100000,
96 .tWC_min = 45000,
97 .tWH_min = 15000,
98 .tWHR_min = 80000,
99 .tWP_min = 25000,
100 .tWW_min = 100000,
101 },
Boris BREZILLON974647e2014-07-11 09:49:42 +0200102 },
103 /* Mode 2 */
104 {
Sascha Hauerb1dd3ca2016-09-15 10:32:47 +0200105 .type = NAND_SDR_IFACE,
106 .timings.sdr = {
Boris Brezillon204e7ec2016-10-01 10:24:02 +0200107 .tCCS_min = 500000,
108 .tR_max = 200000000,
Sascha Hauerb1dd3ca2016-09-15 10:32:47 +0200109 .tADL_min = 400000,
110 .tALH_min = 10000,
111 .tALS_min = 15000,
112 .tAR_min = 10000,
113 .tCEA_max = 30000,
114 .tCEH_min = 20000,
115 .tCH_min = 10000,
116 .tCHZ_max = 50000,
117 .tCLH_min = 10000,
118 .tCLR_min = 10000,
119 .tCLS_min = 15000,
120 .tCOH_min = 15000,
121 .tCS_min = 25000,
122 .tDH_min = 5000,
123 .tDS_min = 15000,
124 .tFEAT_max = 1000000,
125 .tIR_min = 0,
126 .tITC_max = 1000000,
127 .tRC_min = 35000,
128 .tREA_max = 25000,
129 .tREH_min = 15000,
130 .tRHOH_min = 15000,
131 .tRHW_min = 100000,
132 .tRHZ_max = 100000,
133 .tRLOH_min = 0,
134 .tRR_min = 20000,
135 .tRST_max = 500000000,
136 .tWB_max = 100000,
137 .tRP_min = 17000,
138 .tWC_min = 35000,
139 .tWH_min = 15000,
140 .tWHR_min = 80000,
141 .tWP_min = 17000,
142 .tWW_min = 100000,
143 },
Boris BREZILLON974647e2014-07-11 09:49:42 +0200144 },
145 /* Mode 3 */
146 {
Sascha Hauerb1dd3ca2016-09-15 10:32:47 +0200147 .type = NAND_SDR_IFACE,
148 .timings.sdr = {
Boris Brezillon204e7ec2016-10-01 10:24:02 +0200149 .tCCS_min = 500000,
150 .tR_max = 200000000,
Sascha Hauerb1dd3ca2016-09-15 10:32:47 +0200151 .tADL_min = 400000,
152 .tALH_min = 5000,
153 .tALS_min = 10000,
154 .tAR_min = 10000,
155 .tCEA_max = 25000,
156 .tCEH_min = 20000,
157 .tCH_min = 5000,
158 .tCHZ_max = 50000,
159 .tCLH_min = 5000,
160 .tCLR_min = 10000,
161 .tCLS_min = 10000,
162 .tCOH_min = 15000,
163 .tCS_min = 25000,
164 .tDH_min = 5000,
165 .tDS_min = 10000,
166 .tFEAT_max = 1000000,
167 .tIR_min = 0,
168 .tITC_max = 1000000,
169 .tRC_min = 30000,
170 .tREA_max = 20000,
171 .tREH_min = 10000,
172 .tRHOH_min = 15000,
173 .tRHW_min = 100000,
174 .tRHZ_max = 100000,
175 .tRLOH_min = 0,
176 .tRP_min = 15000,
177 .tRR_min = 20000,
178 .tRST_max = 500000000,
179 .tWB_max = 100000,
180 .tWC_min = 30000,
181 .tWH_min = 10000,
182 .tWHR_min = 80000,
183 .tWP_min = 15000,
184 .tWW_min = 100000,
185 },
Boris BREZILLON974647e2014-07-11 09:49:42 +0200186 },
187 /* Mode 4 */
188 {
Sascha Hauerb1dd3ca2016-09-15 10:32:47 +0200189 .type = NAND_SDR_IFACE,
190 .timings.sdr = {
Boris Brezillon204e7ec2016-10-01 10:24:02 +0200191 .tCCS_min = 500000,
192 .tR_max = 200000000,
Sascha Hauerb1dd3ca2016-09-15 10:32:47 +0200193 .tADL_min = 400000,
194 .tALH_min = 5000,
195 .tALS_min = 10000,
196 .tAR_min = 10000,
197 .tCEA_max = 25000,
198 .tCEH_min = 20000,
199 .tCH_min = 5000,
200 .tCHZ_max = 30000,
201 .tCLH_min = 5000,
202 .tCLR_min = 10000,
203 .tCLS_min = 10000,
204 .tCOH_min = 15000,
205 .tCS_min = 20000,
206 .tDH_min = 5000,
207 .tDS_min = 10000,
208 .tFEAT_max = 1000000,
209 .tIR_min = 0,
210 .tITC_max = 1000000,
211 .tRC_min = 25000,
212 .tREA_max = 20000,
213 .tREH_min = 10000,
214 .tRHOH_min = 15000,
215 .tRHW_min = 100000,
216 .tRHZ_max = 100000,
217 .tRLOH_min = 5000,
218 .tRP_min = 12000,
219 .tRR_min = 20000,
220 .tRST_max = 500000000,
221 .tWB_max = 100000,
222 .tWC_min = 25000,
223 .tWH_min = 10000,
224 .tWHR_min = 80000,
225 .tWP_min = 12000,
226 .tWW_min = 100000,
227 },
Boris BREZILLON974647e2014-07-11 09:49:42 +0200228 },
229 /* Mode 5 */
230 {
Sascha Hauerb1dd3ca2016-09-15 10:32:47 +0200231 .type = NAND_SDR_IFACE,
232 .timings.sdr = {
Boris Brezillon204e7ec2016-10-01 10:24:02 +0200233 .tCCS_min = 500000,
234 .tR_max = 200000000,
Sascha Hauerb1dd3ca2016-09-15 10:32:47 +0200235 .tADL_min = 400000,
236 .tALH_min = 5000,
237 .tALS_min = 10000,
238 .tAR_min = 10000,
239 .tCEA_max = 25000,
240 .tCEH_min = 20000,
241 .tCH_min = 5000,
242 .tCHZ_max = 30000,
243 .tCLH_min = 5000,
244 .tCLR_min = 10000,
245 .tCLS_min = 10000,
246 .tCOH_min = 15000,
247 .tCS_min = 15000,
248 .tDH_min = 5000,
249 .tDS_min = 7000,
250 .tFEAT_max = 1000000,
251 .tIR_min = 0,
252 .tITC_max = 1000000,
253 .tRC_min = 20000,
254 .tREA_max = 16000,
255 .tREH_min = 7000,
256 .tRHOH_min = 15000,
257 .tRHW_min = 100000,
258 .tRHZ_max = 100000,
259 .tRLOH_min = 5000,
260 .tRP_min = 10000,
261 .tRR_min = 20000,
262 .tRST_max = 500000000,
263 .tWB_max = 100000,
264 .tWC_min = 20000,
265 .tWH_min = 7000,
266 .tWHR_min = 80000,
267 .tWP_min = 10000,
268 .tWW_min = 100000,
269 },
Boris BREZILLON974647e2014-07-11 09:49:42 +0200270 },
271};
272
273/**
274 * onfi_async_timing_mode_to_sdr_timings - [NAND Interface] Retrieve NAND
275 * timings according to the given ONFI timing mode
276 * @mode: ONFI timing mode
277 */
278const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode)
279{
280 if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings))
281 return ERR_PTR(-EINVAL);
282
Sascha Hauerb1dd3ca2016-09-15 10:32:47 +0200283 return &onfi_sdr_timings[mode].timings.sdr;
Boris BREZILLON974647e2014-07-11 09:49:42 +0200284}
285EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings);
Sascha Hauerb88730a2016-09-15 10:32:48 +0200286
287/**
Miquel Raynal17fa8042017-11-30 18:01:31 +0100288 * onfi_fill_data_interface - [NAND Interface] Initialize a data interface from
Sascha Hauerb88730a2016-09-15 10:32:48 +0200289 * given ONFI mode
Sascha Hauerb88730a2016-09-15 10:32:48 +0200290 * @mode: The ONFI timing mode
291 */
Miquel Raynal17fa8042017-11-30 18:01:31 +0100292int onfi_fill_data_interface(struct nand_chip *chip,
Sascha Hauerb88730a2016-09-15 10:32:48 +0200293 enum nand_data_interface_type type,
294 int timing_mode)
295{
Miquel Raynal17fa8042017-11-30 18:01:31 +0100296 struct nand_data_interface *iface = &chip->data_interface;
297
Sascha Hauerb88730a2016-09-15 10:32:48 +0200298 if (type != NAND_SDR_IFACE)
299 return -EINVAL;
300
301 if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings))
302 return -EINVAL;
303
304 *iface = onfi_sdr_timings[timing_mode];
305
306 /*
Boris Brezillon204e7ec2016-10-01 10:24:02 +0200307 * Initialize timings that cannot be deduced from timing mode:
Miquel Raynal6a943382018-07-14 12:23:54 +0200308 * tPROG, tBERS, tR and tCCS.
Sascha Hauerb88730a2016-09-15 10:32:48 +0200309 * These information are part of the ONFI parameter page.
310 */
Miquel Raynala97421c2018-03-19 14:47:27 +0100311 if (chip->parameters.onfi.version) {
312 struct nand_parameters *params = &chip->parameters;
Boris Brezillon204e7ec2016-10-01 10:24:02 +0200313 struct nand_sdr_timings *timings = &iface->timings.sdr;
314
315 /* microseconds -> picoseconds */
Miquel Raynala97421c2018-03-19 14:47:27 +0100316 timings->tPROG_max = 1000000ULL * params->onfi.tPROG;
317 timings->tBERS_max = 1000000ULL * params->onfi.tBERS;
318 timings->tR_max = 1000000ULL * params->onfi.tR;
Boris Brezillon204e7ec2016-10-01 10:24:02 +0200319
320 /* nanoseconds -> picoseconds */
Miquel Raynala97421c2018-03-19 14:47:27 +0100321 timings->tCCS_min = 1000UL * params->onfi.tCCS;
Miquel Raynal6a943382018-07-14 12:23:54 +0200322 } else {
323 struct nand_sdr_timings *timings = &iface->timings.sdr;
324 /*
325 * For non-ONFI chips we use the highest possible value for
326 * tPROG and tBERS. tR and tCCS will take the default values
327 * precised in the ONFI specification for timing mode 0,
328 * respectively 200us and 500ns.
329 */
330
331 /* microseconds -> picoseconds */
332 timings->tPROG_max = 1000000ULL * ONFI_DYN_TIMING_MAX;
333 timings->tBERS_max = 1000000ULL * ONFI_DYN_TIMING_MAX;
334 timings->tR_max = 1000000ULL * 200000000ULL;
335
336 /* nanoseconds -> picoseconds */
337 timings->tCCS_min = 1000UL * 500000;
Boris Brezillon204e7ec2016-10-01 10:24:02 +0200338 }
Sascha Hauerb88730a2016-09-15 10:32:48 +0200339
340 return 0;
341}
Miquel Raynal17fa8042017-11-30 18:01:31 +0100342EXPORT_SYMBOL(onfi_fill_data_interface);