1 /* 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> 14 #include <linux/mtd/rawnand.h> 15 16 static const struct nand_data_interface onfi_sdr_timings[] = { 17 /* Mode 0 */ 18 { 19 .type = NAND_SDR_IFACE, 20 .timings.sdr = { 21 .tCCS_min = 500000, 22 .tR_max = 200000000, 23 .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 }, 58 }, 59 /* Mode 1 */ 60 { 61 .type = NAND_SDR_IFACE, 62 .timings.sdr = { 63 .tCCS_min = 500000, 64 .tR_max = 200000000, 65 .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 }, 100 }, 101 /* Mode 2 */ 102 { 103 .type = NAND_SDR_IFACE, 104 .timings.sdr = { 105 .tCCS_min = 500000, 106 .tR_max = 200000000, 107 .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 }, 142 }, 143 /* Mode 3 */ 144 { 145 .type = NAND_SDR_IFACE, 146 .timings.sdr = { 147 .tCCS_min = 500000, 148 .tR_max = 200000000, 149 .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 }, 184 }, 185 /* Mode 4 */ 186 { 187 .type = NAND_SDR_IFACE, 188 .timings.sdr = { 189 .tCCS_min = 500000, 190 .tR_max = 200000000, 191 .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 }, 226 }, 227 /* Mode 5 */ 228 { 229 .type = NAND_SDR_IFACE, 230 .timings.sdr = { 231 .tCCS_min = 500000, 232 .tR_max = 200000000, 233 .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 }, 268 }, 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 */ 276 const 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 281 return &onfi_sdr_timings[mode].timings.sdr; 282 } 283 EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings); 284 285 /** 286 * onfi_fill_data_interface - [NAND Interface] Initialize a data interface from 287 * given ONFI mode 288 * @mode: The ONFI timing mode 289 */ 290 int onfi_fill_data_interface(struct nand_chip *chip, 291 enum nand_data_interface_type type, 292 int timing_mode) 293 { 294 struct nand_data_interface *iface = &chip->data_interface; 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 /* 305 * Initialize timings that cannot be deduced from timing mode: 306 * tR, tPROG, tCCS, ... 307 * These information are part of the ONFI parameter page. 308 */ 309 if (chip->parameters.onfi.version) { 310 struct nand_parameters *params = &chip->parameters; 311 struct nand_sdr_timings *timings = &iface->timings.sdr; 312 313 /* microseconds -> picoseconds */ 314 timings->tPROG_max = 1000000ULL * params->onfi.tPROG; 315 timings->tBERS_max = 1000000ULL * params->onfi.tBERS; 316 timings->tR_max = 1000000ULL * params->onfi.tR; 317 318 /* nanoseconds -> picoseconds */ 319 timings->tCCS_min = 1000UL * params->onfi.tCCS; 320 } 321 322 return 0; 323 } 324 EXPORT_SYMBOL(onfi_fill_data_interface); 325