Commit | Line | Data |
---|---|---|
a1452a37 DW |
1 | /* |
2 | * Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org> et al. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program; if not, write to the Free Software | |
16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
17 | * | |
1da177e4 LT |
18 | */ |
19 | ||
20 | #ifndef __MTD_CFI_H__ | |
21 | #define __MTD_CFI_H__ | |
22 | ||
1da177e4 LT |
23 | #include <linux/delay.h> |
24 | #include <linux/types.h> | |
187f1882 | 25 | #include <linux/bug.h> |
1da177e4 LT |
26 | #include <linux/interrupt.h> |
27 | #include <linux/mtd/flashchip.h> | |
28 | #include <linux/mtd/map.h> | |
29 | #include <linux/mtd/cfi_endian.h> | |
2e489e07 | 30 | #include <linux/mtd/xip.h> |
1da177e4 LT |
31 | |
32 | #ifdef CONFIG_MTD_CFI_I1 | |
33 | #define cfi_interleave(cfi) 1 | |
34 | #define cfi_interleave_is_1(cfi) (cfi_interleave(cfi) == 1) | |
35 | #else | |
36 | #define cfi_interleave_is_1(cfi) (0) | |
37 | #endif | |
38 | ||
39 | #ifdef CONFIG_MTD_CFI_I2 | |
40 | # ifdef cfi_interleave | |
41 | # undef cfi_interleave | |
42 | # define cfi_interleave(cfi) ((cfi)->interleave) | |
43 | # else | |
44 | # define cfi_interleave(cfi) 2 | |
45 | # endif | |
46 | #define cfi_interleave_is_2(cfi) (cfi_interleave(cfi) == 2) | |
47 | #else | |
48 | #define cfi_interleave_is_2(cfi) (0) | |
49 | #endif | |
50 | ||
51 | #ifdef CONFIG_MTD_CFI_I4 | |
52 | # ifdef cfi_interleave | |
53 | # undef cfi_interleave | |
54 | # define cfi_interleave(cfi) ((cfi)->interleave) | |
55 | # else | |
56 | # define cfi_interleave(cfi) 4 | |
57 | # endif | |
58 | #define cfi_interleave_is_4(cfi) (cfi_interleave(cfi) == 4) | |
59 | #else | |
60 | #define cfi_interleave_is_4(cfi) (0) | |
61 | #endif | |
62 | ||
63 | #ifdef CONFIG_MTD_CFI_I8 | |
64 | # ifdef cfi_interleave | |
65 | # undef cfi_interleave | |
66 | # define cfi_interleave(cfi) ((cfi)->interleave) | |
67 | # else | |
68 | # define cfi_interleave(cfi) 8 | |
69 | # endif | |
70 | #define cfi_interleave_is_8(cfi) (cfi_interleave(cfi) == 8) | |
71 | #else | |
72 | #define cfi_interleave_is_8(cfi) (0) | |
73 | #endif | |
74 | ||
241651d0 DW |
75 | #ifndef cfi_interleave |
76 | #warning No CONFIG_MTD_CFI_Ix selected. No NOR chip support can work. | |
77 | static inline int cfi_interleave(void *cfi) | |
78 | { | |
79 | BUG(); | |
80 | return 0; | |
81 | } | |
82 | #endif | |
83 | ||
1da177e4 LT |
84 | static inline int cfi_interleave_supported(int i) |
85 | { | |
86 | switch (i) { | |
87 | #ifdef CONFIG_MTD_CFI_I1 | |
88 | case 1: | |
89 | #endif | |
90 | #ifdef CONFIG_MTD_CFI_I2 | |
91 | case 2: | |
92 | #endif | |
93 | #ifdef CONFIG_MTD_CFI_I4 | |
94 | case 4: | |
95 | #endif | |
96 | #ifdef CONFIG_MTD_CFI_I8 | |
97 | case 8: | |
98 | #endif | |
99 | return 1; | |
100 | ||
101 | default: | |
102 | return 0; | |
103 | } | |
104 | } | |
105 | ||
106 | ||
61ecfa87 TG |
107 | /* NB: these values must represents the number of bytes needed to meet the |
108 | * device type (x8, x16, x32). Eg. a 32 bit device is 4 x 8 bytes. | |
1da177e4 LT |
109 | * These numbers are used in calculations. |
110 | */ | |
111 | #define CFI_DEVICETYPE_X8 (8 / 8) | |
112 | #define CFI_DEVICETYPE_X16 (16 / 8) | |
113 | #define CFI_DEVICETYPE_X32 (32 / 8) | |
114 | #define CFI_DEVICETYPE_X64 (64 / 8) | |
115 | ||
de7921f0 BS |
116 | |
117 | /* Device Interface Code Assignments from the "Common Flash Memory Interface | |
118 | * Publication 100" dated December 1, 2001. | |
119 | */ | |
120 | #define CFI_INTERFACE_X8_ASYNC 0x0000 | |
121 | #define CFI_INTERFACE_X16_ASYNC 0x0001 | |
122 | #define CFI_INTERFACE_X8_BY_X16_ASYNC 0x0002 | |
123 | #define CFI_INTERFACE_X32_ASYNC 0x0003 | |
124 | #define CFI_INTERFACE_X16_BY_X32_ASYNC 0x0005 | |
125 | #define CFI_INTERFACE_NOT_ALLOWED 0xffff | |
126 | ||
127 | ||
1da177e4 LT |
128 | /* NB: We keep these structures in memory in HOST byteorder, except |
129 | * where individually noted. | |
130 | */ | |
131 | ||
132 | /* Basic Query Structure */ | |
133 | struct cfi_ident { | |
134 | uint8_t qry[3]; | |
135 | uint16_t P_ID; | |
136 | uint16_t P_ADR; | |
137 | uint16_t A_ID; | |
138 | uint16_t A_ADR; | |
139 | uint8_t VccMin; | |
140 | uint8_t VccMax; | |
141 | uint8_t VppMin; | |
142 | uint8_t VppMax; | |
143 | uint8_t WordWriteTimeoutTyp; | |
144 | uint8_t BufWriteTimeoutTyp; | |
145 | uint8_t BlockEraseTimeoutTyp; | |
146 | uint8_t ChipEraseTimeoutTyp; | |
147 | uint8_t WordWriteTimeoutMax; | |
148 | uint8_t BufWriteTimeoutMax; | |
149 | uint8_t BlockEraseTimeoutMax; | |
150 | uint8_t ChipEraseTimeoutMax; | |
151 | uint8_t DevSize; | |
152 | uint16_t InterfaceDesc; | |
153 | uint16_t MaxBufWriteSize; | |
154 | uint8_t NumEraseRegions; | |
155 | uint32_t EraseRegionInfo[0]; /* Not host ordered */ | |
31f75462 | 156 | } __packed; |
1da177e4 LT |
157 | |
158 | /* Extended Query Structure for both PRI and ALT */ | |
159 | ||
160 | struct cfi_extquery { | |
161 | uint8_t pri[3]; | |
162 | uint8_t MajorVersion; | |
163 | uint8_t MinorVersion; | |
31f75462 | 164 | } __packed; |
1da177e4 LT |
165 | |
166 | /* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */ | |
167 | ||
168 | struct cfi_pri_intelext { | |
169 | uint8_t pri[3]; | |
170 | uint8_t MajorVersion; | |
171 | uint8_t MinorVersion; | |
172 | uint32_t FeatureSupport; /* if bit 31 is set then an additional uint32_t feature | |
173 | block follows - FIXME - not currently supported */ | |
174 | uint8_t SuspendCmdSupport; | |
175 | uint16_t BlkStatusRegMask; | |
176 | uint8_t VccOptimal; | |
177 | uint8_t VppOptimal; | |
178 | uint8_t NumProtectionFields; | |
179 | uint16_t ProtRegAddr; | |
180 | uint8_t FactProtRegSize; | |
181 | uint8_t UserProtRegSize; | |
182 | uint8_t extra[0]; | |
31f75462 | 183 | } __packed; |
1da177e4 | 184 | |
72b56a2d NP |
185 | struct cfi_intelext_otpinfo { |
186 | uint32_t ProtRegAddr; | |
187 | uint16_t FactGroups; | |
188 | uint8_t FactProtRegSize; | |
189 | uint16_t UserGroups; | |
190 | uint8_t UserProtRegSize; | |
31f75462 | 191 | } __packed; |
72b56a2d | 192 | |
1da177e4 LT |
193 | struct cfi_intelext_blockinfo { |
194 | uint16_t NumIdentBlocks; | |
195 | uint16_t BlockSize; | |
196 | uint16_t MinBlockEraseCycles; | |
197 | uint8_t BitsPerCell; | |
198 | uint8_t BlockCap; | |
31f75462 | 199 | } __packed; |
1da177e4 LT |
200 | |
201 | struct cfi_intelext_regioninfo { | |
202 | uint16_t NumIdentPartitions; | |
203 | uint8_t NumOpAllowed; | |
204 | uint8_t NumOpAllowedSimProgMode; | |
205 | uint8_t NumOpAllowedSimEraMode; | |
206 | uint8_t NumBlockTypes; | |
207 | struct cfi_intelext_blockinfo BlockTypes[1]; | |
31f75462 | 208 | } __packed; |
1da177e4 | 209 | |
638d9838 NP |
210 | struct cfi_intelext_programming_regioninfo { |
211 | uint8_t ProgRegShift; | |
212 | uint8_t Reserved1; | |
213 | uint8_t ControlValid; | |
214 | uint8_t Reserved2; | |
215 | uint8_t ControlInvalid; | |
216 | uint8_t Reserved3; | |
31f75462 | 217 | } __packed; |
638d9838 | 218 | |
1da177e4 LT |
219 | /* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */ |
220 | ||
221 | struct cfi_pri_amdstd { | |
222 | uint8_t pri[3]; | |
223 | uint8_t MajorVersion; | |
224 | uint8_t MinorVersion; | |
225 | uint8_t SiliconRevision; /* bits 1-0: Address Sensitive Unlock */ | |
226 | uint8_t EraseSuspend; | |
227 | uint8_t BlkProt; | |
228 | uint8_t TmpBlkUnprotect; | |
229 | uint8_t BlkProtUnprot; | |
230 | uint8_t SimultaneousOps; | |
231 | uint8_t BurstMode; | |
232 | uint8_t PageMode; | |
233 | uint8_t VppMin; | |
234 | uint8_t VppMax; | |
235 | uint8_t TopBottom; | |
31f75462 | 236 | } __packed; |
1da177e4 | 237 | |
5b0c5c2c HS |
238 | /* Vendor-Specific PRI for Atmel chips (command set 0x0002) */ |
239 | ||
240 | struct cfi_pri_atmel { | |
241 | uint8_t pri[3]; | |
242 | uint8_t MajorVersion; | |
243 | uint8_t MinorVersion; | |
244 | uint8_t Features; | |
245 | uint8_t BottomBoot; | |
246 | uint8_t BurstMode; | |
247 | uint8_t PageMode; | |
31f75462 | 248 | } __packed; |
5b0c5c2c | 249 | |
1da177e4 LT |
250 | struct cfi_pri_query { |
251 | uint8_t NumFields; | |
252 | uint32_t ProtField[1]; /* Not host ordered */ | |
31f75462 | 253 | } __packed; |
1da177e4 LT |
254 | |
255 | struct cfi_bri_query { | |
256 | uint8_t PageModeReadCap; | |
257 | uint8_t NumFields; | |
258 | uint32_t ConfField[1]; /* Not host ordered */ | |
31f75462 | 259 | } __packed; |
1da177e4 LT |
260 | |
261 | #define P_ID_NONE 0x0000 | |
262 | #define P_ID_INTEL_EXT 0x0001 | |
263 | #define P_ID_AMD_STD 0x0002 | |
264 | #define P_ID_INTEL_STD 0x0003 | |
265 | #define P_ID_AMD_EXT 0x0004 | |
266 | #define P_ID_WINBOND 0x0006 | |
267 | #define P_ID_ST_ADV 0x0020 | |
268 | #define P_ID_MITSUBISHI_STD 0x0100 | |
269 | #define P_ID_MITSUBISHI_EXT 0x0101 | |
270 | #define P_ID_SST_PAGE 0x0102 | |
54b93a49 | 271 | #define P_ID_SST_OLD 0x0701 |
1da177e4 LT |
272 | #define P_ID_INTEL_PERFORMANCE 0x0200 |
273 | #define P_ID_INTEL_DATA 0x0210 | |
274 | #define P_ID_RESERVED 0xffff | |
275 | ||
276 | ||
277 | #define CFI_MODE_CFI 1 | |
278 | #define CFI_MODE_JEDEC 0 | |
279 | ||
280 | struct cfi_private { | |
281 | uint16_t cmdset; | |
282 | void *cmdset_priv; | |
283 | int interleave; | |
284 | int device_type; | |
285 | int cfi_mode; /* Are we a JEDEC device pretending to be CFI? */ | |
286 | int addr_unlock1; | |
287 | int addr_unlock2; | |
288 | struct mtd_info *(*cmdset_setup)(struct map_info *); | |
289 | struct cfi_ident *cfiq; /* For now only one. We insist that all devs | |
290 | must be of the same type. */ | |
291 | int mfr, id; | |
292 | int numchips; | |
08968041 | 293 | map_word sector_erase_cmd; |
1da177e4 LT |
294 | unsigned long chipshift; /* Because they're of the same type */ |
295 | const char *im_name; /* inter_module name for cmdset_setup */ | |
296 | struct flchip chips[0]; /* per-chip data structure for each chip */ | |
297 | }; | |
298 | ||
4612c715 DV |
299 | uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, |
300 | struct map_info *map, struct cfi_private *cfi); | |
1da177e4 | 301 | |
4612c715 | 302 | map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi); |
1da177e4 LT |
303 | #define CMD(x) cfi_build_cmd((x), map, cfi) |
304 | ||
4612c715 DV |
305 | unsigned long cfi_merge_status(map_word val, struct map_info *map, |
306 | struct cfi_private *cfi); | |
c927cd3a TG |
307 | #define MERGESTATUS(x) cfi_merge_status((x), map, cfi) |
308 | ||
4612c715 | 309 | uint32_t cfi_send_gen_cmd(u_char cmd, uint32_t cmd_addr, uint32_t base, |
1da177e4 | 310 | struct map_info *map, struct cfi_private *cfi, |
4612c715 | 311 | int type, map_word *prev_val); |
1da177e4 LT |
312 | |
313 | static inline uint8_t cfi_read_query(struct map_info *map, uint32_t addr) | |
314 | { | |
315 | map_word val = map_read(map, addr); | |
316 | ||
317 | if (map_bankwidth_is_1(map)) { | |
318 | return val.x[0]; | |
319 | } else if (map_bankwidth_is_2(map)) { | |
8e987465 | 320 | return cfi16_to_cpu(map, val.x[0]); |
987d2401 TP |
321 | } else { |
322 | /* No point in a 64-bit byteswap since that would just be | |
323 | swapping the responses from different chips, and we are | |
324 | only interested in one chip (a representative sample) */ | |
8e987465 | 325 | return cfi32_to_cpu(map, val.x[0]); |
987d2401 TP |
326 | } |
327 | } | |
328 | ||
329 | static inline uint16_t cfi_read_query16(struct map_info *map, uint32_t addr) | |
330 | { | |
331 | map_word val = map_read(map, addr); | |
332 | ||
333 | if (map_bankwidth_is_1(map)) { | |
334 | return val.x[0] & 0xff; | |
335 | } else if (map_bankwidth_is_2(map)) { | |
8e987465 | 336 | return cfi16_to_cpu(map, val.x[0]); |
1da177e4 LT |
337 | } else { |
338 | /* No point in a 64-bit byteswap since that would just be | |
339 | swapping the responses from different chips, and we are | |
340 | only interested in one chip (a representative sample) */ | |
8e987465 | 341 | return cfi32_to_cpu(map, val.x[0]); |
1da177e4 LT |
342 | } |
343 | } | |
344 | ||
4612c715 | 345 | void cfi_udelay(int us); |
1da177e4 | 346 | |
c314dfdc DW |
347 | int __xipram cfi_qry_present(struct map_info *map, __u32 base, |
348 | struct cfi_private *cfi); | |
349 | int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map, | |
350 | struct cfi_private *cfi); | |
351 | void __xipram cfi_qry_mode_off(uint32_t base, struct map_info *map, | |
352 | struct cfi_private *cfi); | |
2e489e07 | 353 | |
1da177e4 LT |
354 | struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size, |
355 | const char* name); | |
356 | struct cfi_fixup { | |
357 | uint16_t mfr; | |
358 | uint16_t id; | |
cc318222 | 359 | void (*fixup)(struct mtd_info *mtd); |
1da177e4 LT |
360 | }; |
361 | ||
ae731822 WS |
362 | #define CFI_MFR_ANY 0xFFFF |
363 | #define CFI_ID_ANY 0xFFFF | |
364 | #define CFI_MFR_CONTINUATION 0x007F | |
1da177e4 | 365 | |
f3e69c65 | 366 | #define CFI_MFR_AMD 0x0001 |
1065cda8 | 367 | #define CFI_MFR_AMIC 0x0037 |
f3e69c65 | 368 | #define CFI_MFR_ATMEL 0x001F |
ae731822 WS |
369 | #define CFI_MFR_EON 0x001C |
370 | #define CFI_MFR_FUJITSU 0x0004 | |
371 | #define CFI_MFR_HYUNDAI 0x00AD | |
f3e69c65 GL |
372 | #define CFI_MFR_INTEL 0x0089 |
373 | #define CFI_MFR_MACRONIX 0x00C2 | |
ae731822 WS |
374 | #define CFI_MFR_NEC 0x0010 |
375 | #define CFI_MFR_PMC 0x009D | |
f3e69c65 | 376 | #define CFI_MFR_SAMSUNG 0x00EC |
ae731822 | 377 | #define CFI_MFR_SHARP 0x00B0 |
f3e69c65 GL |
378 | #define CFI_MFR_SST 0x00BF |
379 | #define CFI_MFR_ST 0x0020 /* STMicroelectronics */ | |
ae731822 WS |
380 | #define CFI_MFR_TOSHIBA 0x0098 |
381 | #define CFI_MFR_WINBOND 0x00DA | |
1da177e4 LT |
382 | |
383 | void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup* fixups); | |
384 | ||
385 | typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip, | |
386 | unsigned long adr, int len, void *thunk); | |
387 | ||
388 | int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, | |
389 | loff_t ofs, size_t len, void *thunk); | |
390 | ||
391 | ||
392 | #endif /* __MTD_CFI_H__ */ |