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 <common.h> 12 #include <linux/kernel.h> 13 #include <linux/mtd/rawnand.h> 14 15 static const struct nand_data_interface onfi_sdr_timings[] = { 16 /* Mode 0 */ 17 { 18 .type = NAND_SDR_IFACE, 19 .timings.sdr = { 20 .tCCS_min = 500000, 21 .tR_max = 200000000, 22 .tADL_min = 400000, 23 .tALH_min = 20000, 24 .tALS_min = 50000, 25 .tAR_min = 25000, 26 .tCEA_max = 100000, 27 .tCEH_min = 20000, 28 .tCH_min = 20000, 29 .tCHZ_max = 100000, 30 .tCLH_min = 20000, 31 .tCLR_min = 20000, 32 .tCLS_min = 50000, 33 .tCOH_min = 0, 34 .tCS_min = 70000, 35 .tDH_min = 20000, 36 .tDS_min = 40000, 37 .tFEAT_max = 1000000, 38 .tIR_min = 10000, 39 .tITC_max = 1000000, 40 .tRC_min = 100000, 41 .tREA_max = 40000, 42 .tREH_min = 30000, 43 .tRHOH_min = 0, 44 .tRHW_min = 200000, 45 .tRHZ_max = 200000, 46 .tRLOH_min = 0, 47 .tRP_min = 50000, 48 .tRR_min = 40000, 49 .tRST_max = 250000000000ULL, 50 .tWB_max = 200000, 51 .tWC_min = 100000, 52 .tWH_min = 30000, 53 .tWHR_min = 120000, 54 .tWP_min = 50000, 55 .tWW_min = 100000, 56 }, 57 }, 58 /* Mode 1 */ 59 { 60 .type = NAND_SDR_IFACE, 61 .timings.sdr = { 62 .tCCS_min = 500000, 63 .tR_max = 200000000, 64 .tADL_min = 400000, 65 .tALH_min = 10000, 66 .tALS_min = 25000, 67 .tAR_min = 10000, 68 .tCEA_max = 45000, 69 .tCEH_min = 20000, 70 .tCH_min = 10000, 71 .tCHZ_max = 50000, 72 .tCLH_min = 10000, 73 .tCLR_min = 10000, 74 .tCLS_min = 25000, 75 .tCOH_min = 15000, 76 .tCS_min = 35000, 77 .tDH_min = 10000, 78 .tDS_min = 20000, 79 .tFEAT_max = 1000000, 80 .tIR_min = 0, 81 .tITC_max = 1000000, 82 .tRC_min = 50000, 83 .tREA_max = 30000, 84 .tREH_min = 15000, 85 .tRHOH_min = 15000, 86 .tRHW_min = 100000, 87 .tRHZ_max = 100000, 88 .tRLOH_min = 0, 89 .tRP_min = 25000, 90 .tRR_min = 20000, 91 .tRST_max = 500000000, 92 .tWB_max = 100000, 93 .tWC_min = 45000, 94 .tWH_min = 15000, 95 .tWHR_min = 80000, 96 .tWP_min = 25000, 97 .tWW_min = 100000, 98 }, 99 }, 100 /* Mode 2 */ 101 { 102 .type = NAND_SDR_IFACE, 103 .timings.sdr = { 104 .tCCS_min = 500000, 105 .tR_max = 200000000, 106 .tADL_min = 400000, 107 .tALH_min = 10000, 108 .tALS_min = 15000, 109 .tAR_min = 10000, 110 .tCEA_max = 30000, 111 .tCEH_min = 20000, 112 .tCH_min = 10000, 113 .tCHZ_max = 50000, 114 .tCLH_min = 10000, 115 .tCLR_min = 10000, 116 .tCLS_min = 15000, 117 .tCOH_min = 15000, 118 .tCS_min = 25000, 119 .tDH_min = 5000, 120 .tDS_min = 15000, 121 .tFEAT_max = 1000000, 122 .tIR_min = 0, 123 .tITC_max = 1000000, 124 .tRC_min = 35000, 125 .tREA_max = 25000, 126 .tREH_min = 15000, 127 .tRHOH_min = 15000, 128 .tRHW_min = 100000, 129 .tRHZ_max = 100000, 130 .tRLOH_min = 0, 131 .tRR_min = 20000, 132 .tRST_max = 500000000, 133 .tWB_max = 100000, 134 .tRP_min = 17000, 135 .tWC_min = 35000, 136 .tWH_min = 15000, 137 .tWHR_min = 80000, 138 .tWP_min = 17000, 139 .tWW_min = 100000, 140 }, 141 }, 142 /* Mode 3 */ 143 { 144 .type = NAND_SDR_IFACE, 145 .timings.sdr = { 146 .tCCS_min = 500000, 147 .tR_max = 200000000, 148 .tADL_min = 400000, 149 .tALH_min = 5000, 150 .tALS_min = 10000, 151 .tAR_min = 10000, 152 .tCEA_max = 25000, 153 .tCEH_min = 20000, 154 .tCH_min = 5000, 155 .tCHZ_max = 50000, 156 .tCLH_min = 5000, 157 .tCLR_min = 10000, 158 .tCLS_min = 10000, 159 .tCOH_min = 15000, 160 .tCS_min = 25000, 161 .tDH_min = 5000, 162 .tDS_min = 10000, 163 .tFEAT_max = 1000000, 164 .tIR_min = 0, 165 .tITC_max = 1000000, 166 .tRC_min = 30000, 167 .tREA_max = 20000, 168 .tREH_min = 10000, 169 .tRHOH_min = 15000, 170 .tRHW_min = 100000, 171 .tRHZ_max = 100000, 172 .tRLOH_min = 0, 173 .tRP_min = 15000, 174 .tRR_min = 20000, 175 .tRST_max = 500000000, 176 .tWB_max = 100000, 177 .tWC_min = 30000, 178 .tWH_min = 10000, 179 .tWHR_min = 80000, 180 .tWP_min = 15000, 181 .tWW_min = 100000, 182 }, 183 }, 184 /* Mode 4 */ 185 { 186 .type = NAND_SDR_IFACE, 187 .timings.sdr = { 188 .tCCS_min = 500000, 189 .tR_max = 200000000, 190 .tADL_min = 400000, 191 .tALH_min = 5000, 192 .tALS_min = 10000, 193 .tAR_min = 10000, 194 .tCEA_max = 25000, 195 .tCEH_min = 20000, 196 .tCH_min = 5000, 197 .tCHZ_max = 30000, 198 .tCLH_min = 5000, 199 .tCLR_min = 10000, 200 .tCLS_min = 10000, 201 .tCOH_min = 15000, 202 .tCS_min = 20000, 203 .tDH_min = 5000, 204 .tDS_min = 10000, 205 .tFEAT_max = 1000000, 206 .tIR_min = 0, 207 .tITC_max = 1000000, 208 .tRC_min = 25000, 209 .tREA_max = 20000, 210 .tREH_min = 10000, 211 .tRHOH_min = 15000, 212 .tRHW_min = 100000, 213 .tRHZ_max = 100000, 214 .tRLOH_min = 5000, 215 .tRP_min = 12000, 216 .tRR_min = 20000, 217 .tRST_max = 500000000, 218 .tWB_max = 100000, 219 .tWC_min = 25000, 220 .tWH_min = 10000, 221 .tWHR_min = 80000, 222 .tWP_min = 12000, 223 .tWW_min = 100000, 224 }, 225 }, 226 /* Mode 5 */ 227 { 228 .type = NAND_SDR_IFACE, 229 .timings.sdr = { 230 .tCCS_min = 500000, 231 .tR_max = 200000000, 232 .tADL_min = 400000, 233 .tALH_min = 5000, 234 .tALS_min = 10000, 235 .tAR_min = 10000, 236 .tCEA_max = 25000, 237 .tCEH_min = 20000, 238 .tCH_min = 5000, 239 .tCHZ_max = 30000, 240 .tCLH_min = 5000, 241 .tCLR_min = 10000, 242 .tCLS_min = 10000, 243 .tCOH_min = 15000, 244 .tCS_min = 15000, 245 .tDH_min = 5000, 246 .tDS_min = 7000, 247 .tFEAT_max = 1000000, 248 .tIR_min = 0, 249 .tITC_max = 1000000, 250 .tRC_min = 20000, 251 .tREA_max = 16000, 252 .tREH_min = 7000, 253 .tRHOH_min = 15000, 254 .tRHW_min = 100000, 255 .tRHZ_max = 100000, 256 .tRLOH_min = 5000, 257 .tRP_min = 10000, 258 .tRR_min = 20000, 259 .tRST_max = 500000000, 260 .tWB_max = 100000, 261 .tWC_min = 20000, 262 .tWH_min = 7000, 263 .tWHR_min = 80000, 264 .tWP_min = 10000, 265 .tWW_min = 100000, 266 }, 267 }, 268 }; 269 270 /** 271 * onfi_async_timing_mode_to_sdr_timings - [NAND Interface] Retrieve NAND 272 * timings according to the given ONFI timing mode 273 * @mode: ONFI timing mode 274 */ 275 const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode) 276 { 277 if (mode < 0 || mode >= ARRAY_SIZE(onfi_sdr_timings)) 278 return ERR_PTR(-EINVAL); 279 280 return &onfi_sdr_timings[mode].timings.sdr; 281 } 282 EXPORT_SYMBOL(onfi_async_timing_mode_to_sdr_timings); 283 284 /** 285 * onfi_init_data_interface - [NAND Interface] Initialize a data interface from 286 * given ONFI mode 287 * @iface: The data interface to be initialized 288 * @mode: The ONFI timing mode 289 */ 290 int onfi_init_data_interface(struct nand_chip *chip, 291 struct nand_data_interface *iface, 292 enum nand_data_interface_type type, 293 int timing_mode) 294 { 295 if (type != NAND_SDR_IFACE) 296 return -EINVAL; 297 298 if (timing_mode < 0 || timing_mode >= ARRAY_SIZE(onfi_sdr_timings)) 299 return -EINVAL; 300 301 *iface = onfi_sdr_timings[timing_mode]; 302 303 /* 304 * Initialize timings that cannot be deduced from timing mode: 305 * tR, tPROG, tCCS, ... 306 * These information are part of the ONFI parameter page. 307 */ 308 if (chip->onfi_version) { 309 struct nand_onfi_params *params = &chip->onfi_params; 310 struct nand_sdr_timings *timings = &iface->timings.sdr; 311 312 /* microseconds -> picoseconds */ 313 timings->tPROG_max = 1000000ULL * le16_to_cpu(params->t_prog); 314 timings->tBERS_max = 1000000ULL * le16_to_cpu(params->t_bers); 315 timings->tR_max = 1000000ULL * le16_to_cpu(params->t_r); 316 317 /* nanoseconds -> picoseconds */ 318 timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs); 319 } 320 321 return 0; 322 } 323 EXPORT_SYMBOL(onfi_init_data_interface); 324 325 /** 326 * nand_get_default_data_interface - [NAND Interface] Retrieve NAND 327 * data interface for mode 0. This is used as default timing after 328 * reset. 329 */ 330 const struct nand_data_interface *nand_get_default_data_interface(void) 331 { 332 return &onfi_sdr_timings[0]; 333 } 334 EXPORT_SYMBOL(nand_get_default_data_interface); 335