cfi.h
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:12k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* Common Flash Interface structures 
  2.  * See http://support.intel.com/design/flash/technote/index.htm
  3.  * $Id: cfi.h,v 1.30 2002/02/21 08:27:43 dwmw2 Exp $
  4.  */
  5. #ifndef __MTD_CFI_H__
  6. #define __MTD_CFI_H__
  7. #include <linux/config.h>
  8. #include <linux/delay.h>
  9. #include <linux/types.h>
  10. #include <linux/interrupt.h>
  11. #include <linux/mtd/flashchip.h>
  12. #include <linux/mtd/cfi_endian.h>
  13. /*
  14.  * You can optimize the code size and performance by defining only 
  15.  * the geometry(ies) available on your hardware.
  16.  * CFIDEV_INTERLEAVE_n, where  represents the interleave (number of chips to fill the bus width)
  17.  * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2, 4 or 8 bytes)
  18.  *
  19.  * By default, all (known) geometries are supported.
  20.  */
  21. #ifndef CONFIG_MTD_CFI_GEOMETRY
  22. /* The default case - support all but 64-bit, which has
  23.    a performance penalty */
  24. #define CFIDEV_INTERLEAVE_1 (1)
  25. #define CFIDEV_INTERLEAVE_2 (2)
  26. #define CFIDEV_INTERLEAVE_4 (4)
  27. #define CFIDEV_BUSWIDTH_1 (1)
  28. #define CFIDEV_BUSWIDTH_2 (2)
  29. #define CFIDEV_BUSWIDTH_4 (4)
  30. typedef __u32 cfi_word;
  31. #else
  32. /* Explicitly configured buswidth/interleave support */
  33. #ifdef CONFIG_MTD_CFI_I1
  34. #define CFIDEV_INTERLEAVE_1 (1)
  35. #endif
  36. #ifdef CONFIG_MTD_CFI_I2
  37. #define CFIDEV_INTERLEAVE_2 (2)
  38. #endif
  39. #ifdef CONFIG_MTD_CFI_I4
  40. #define CFIDEV_INTERLEAVE_4 (4)
  41. #endif
  42. #ifdef CONFIG_MTD_CFI_I8
  43. #define CFIDEV_INTERLEAVE_8 (8)
  44. #endif
  45. #ifdef CONFIG_MTD_CFI_B1
  46. #define CFIDEV_BUSWIDTH_1 (1)
  47. #endif
  48. #ifdef CONFIG_MTD_CFI_B2
  49. #define CFIDEV_BUSWIDTH_2 (2)
  50. #endif
  51. #ifdef CONFIG_MTD_CFI_B4
  52. #define CFIDEV_BUSWIDTH_4 (4)
  53. #endif
  54. #ifdef CONFIG_MTD_CFI_B8
  55. #define CFIDEV_BUSWIDTH_8 (8)
  56. #endif
  57. /* pick the largest necessary */
  58. #ifdef CONFIG_MTD_CFI_B8
  59. typedef __u64 cfi_word;
  60. #define CFI_WORD_64
  61. #else  /* CONFIG_MTD_CFI_B8 */
  62. /* All others can use 32-bits. It's probably more efficient than
  63.    the smaller types anyway */
  64. typedef __u32 cfi_word;
  65. #endif /* CONFIG_MTD_CFI_B8 */
  66. #endif
  67. /*
  68.  * The following macros are used to select the code to execute:
  69.  *   cfi_buswidth_is_*()
  70.  *   cfi_interleave_is_*()
  71.  *   [where * is either 1, 2, 4, or 8]
  72.  * Those macros should be used with 'if' statements.  If only one of few
  73.  * geometry arrangements are selected, they expand to constants thus allowing
  74.  * the compiler (most of them being 0) to optimize away all the unneeded code,
  75.  * while still validating the syntax (which is not possible with embedded 
  76.  * #if ... #endif constructs).
  77.  * The exception to this is the 64-bit versions, which need an extension
  78.  * to the cfi_word type, and cause compiler warnings about shifts being
  79.  * out of range.
  80.  */
  81. #ifdef CFIDEV_INTERLEAVE_1
  82. # ifdef CFIDEV_INTERLEAVE
  83. #  undef CFIDEV_INTERLEAVE
  84. #  define CFIDEV_INTERLEAVE (cfi->interleave)
  85. # else
  86. #  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_1
  87. # endif
  88. # define cfi_interleave_is_1() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_1)
  89. #else
  90. # define cfi_interleave_is_1() (0)
  91. #endif
  92. #ifdef CFIDEV_INTERLEAVE_2
  93. # ifdef CFIDEV_INTERLEAVE
  94. #  undef CFIDEV_INTERLEAVE
  95. #  define CFIDEV_INTERLEAVE (cfi->interleave)
  96. # else
  97. #  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_2
  98. # endif
  99. # define cfi_interleave_is_2() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_2)
  100. #else
  101. # define cfi_interleave_is_2() (0)
  102. #endif
  103. #ifdef CFIDEV_INTERLEAVE_4
  104. # ifdef CFIDEV_INTERLEAVE
  105. #  undef CFIDEV_INTERLEAVE
  106. #  define CFIDEV_INTERLEAVE (cfi->interleave)
  107. # else
  108. #  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_4
  109. # endif
  110. # define cfi_interleave_is_4() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_4)
  111. #else
  112. # define cfi_interleave_is_4() (0)
  113. #endif
  114. #ifdef CFIDEV_INTERLEAVE_8
  115. # ifdef CFIDEV_INTERLEAVE
  116. #  undef CFIDEV_INTERLEAVE
  117. #  define CFIDEV_INTERLEAVE (cfi->interleave)
  118. # else
  119. #  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_8
  120. # endif
  121. # define cfi_interleave_is_8() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_8)
  122. #else
  123. # define cfi_interleave_is_8() (0)
  124. #endif
  125. #ifndef CFIDEV_INTERLEAVE
  126. #error You must define at least one interleave to support!
  127. #endif
  128. #ifdef CFIDEV_BUSWIDTH_1
  129. # ifdef CFIDEV_BUSWIDTH
  130. #  undef CFIDEV_BUSWIDTH
  131. #  define CFIDEV_BUSWIDTH (map->buswidth)
  132. # else
  133. #  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_1
  134. # endif
  135. # define cfi_buswidth_is_1() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_1)
  136. #else
  137. # define cfi_buswidth_is_1() (0)
  138. #endif
  139. #ifdef CFIDEV_BUSWIDTH_2
  140. # ifdef CFIDEV_BUSWIDTH
  141. #  undef CFIDEV_BUSWIDTH
  142. #  define CFIDEV_BUSWIDTH (map->buswidth)
  143. # else
  144. #  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_2
  145. # endif
  146. # define cfi_buswidth_is_2() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_2)
  147. #else
  148. # define cfi_buswidth_is_2() (0)
  149. #endif
  150. #ifdef CFIDEV_BUSWIDTH_4
  151. # ifdef CFIDEV_BUSWIDTH
  152. #  undef CFIDEV_BUSWIDTH
  153. #  define CFIDEV_BUSWIDTH (map->buswidth)
  154. # else
  155. #  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_4
  156. # endif
  157. # define cfi_buswidth_is_4() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_4)
  158. #else
  159. # define cfi_buswidth_is_4() (0)
  160. #endif
  161. #ifdef CFIDEV_BUSWIDTH_8
  162. # ifdef CFIDEV_BUSWIDTH
  163. #  undef CFIDEV_BUSWIDTH
  164. #  define CFIDEV_BUSWIDTH (map->buswidth)
  165. # else
  166. #  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_8
  167. # endif
  168. # define cfi_buswidth_is_8() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_8)
  169. #else
  170. # define cfi_buswidth_is_8() (0)
  171. #endif
  172. #ifndef CFIDEV_BUSWIDTH
  173. #error You must define at least one bus width to support!
  174. #endif
  175. /* NB: these values must represents the number of bytes needed to meet the 
  176.  *     device type (x8, x16, x32).  Eg. a 32 bit device is 4 x 8 bytes. 
  177.  *     These numbers are used in calculations.
  178.  */
  179. #define CFI_DEVICETYPE_X8  (8 / 8)
  180. #define CFI_DEVICETYPE_X16 (16 / 8)
  181. #define CFI_DEVICETYPE_X32 (32 / 8)
  182. #define CFI_DEVICETYPE_X64 (64 / 8)
  183. /* NB: We keep these structures in memory in HOST byteorder, except
  184.  * where individually noted.
  185.  */
  186. /* Basic Query Structure */
  187. struct cfi_ident {
  188.   __u8  qry[3];
  189.   __u16 P_ID;
  190.   __u16 P_ADR;
  191.   __u16 A_ID;
  192.   __u16 A_ADR;
  193.   __u8  VccMin;
  194.   __u8  VccMax;
  195.   __u8  VppMin;
  196.   __u8  VppMax;
  197.   __u8  WordWriteTimeoutTyp;
  198.   __u8  BufWriteTimeoutTyp;
  199.   __u8  BlockEraseTimeoutTyp;
  200.   __u8  ChipEraseTimeoutTyp;
  201.   __u8  WordWriteTimeoutMax;
  202.   __u8  BufWriteTimeoutMax;
  203.   __u8  BlockEraseTimeoutMax;
  204.   __u8  ChipEraseTimeoutMax;
  205.   __u8  DevSize;
  206.   __u16 InterfaceDesc;
  207.   __u16 MaxBufWriteSize;
  208.   __u8  NumEraseRegions;
  209.   __u32 EraseRegionInfo[0]; /* Not host ordered */
  210. } __attribute__((packed));
  211. /* Extended Query Structure for both PRI and ALT */
  212. struct cfi_extquery {
  213.   __u8  pri[3];
  214.   __u8  MajorVersion;
  215.   __u8  MinorVersion;
  216. } __attribute__((packed));
  217. /* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */
  218. struct cfi_pri_intelext {
  219.   __u8  pri[3];
  220.   __u8  MajorVersion;
  221.   __u8  MinorVersion;
  222.   __u32 FeatureSupport;
  223.   __u8  SuspendCmdSupport;
  224.   __u16 BlkStatusRegMask;
  225.   __u8  VccOptimal;
  226.   __u8  VppOptimal;
  227.   __u8  NumProtectionFields;
  228.   __u16 ProtRegAddr;
  229.   __u8  FactProtRegSize;
  230.   __u8  UserProtRegSize;
  231. } __attribute__((packed));
  232. struct cfi_pri_query {
  233.   __u8  NumFields;
  234.   __u32 ProtField[1]; /* Not host ordered */
  235. } __attribute__((packed));
  236. struct cfi_bri_query {
  237.   __u8  PageModeReadCap;
  238.   __u8  NumFields;
  239.   __u32 ConfField[1]; /* Not host ordered */
  240. } __attribute__((packed));
  241. #define P_ID_NONE 0
  242. #define P_ID_INTEL_EXT 1
  243. #define P_ID_AMD_STD 2
  244. #define P_ID_INTEL_STD 3
  245. #define P_ID_AMD_EXT 4
  246. #define P_ID_MITSUBISHI_STD 256
  247. #define P_ID_MITSUBISHI_EXT 257
  248. #define P_ID_RESERVED 65535
  249. #define CFI_MODE_CFI 1
  250. #define CFI_MODE_JEDEC 0
  251. struct cfi_private {
  252. __u16 cmdset;
  253. void *cmdset_priv;
  254. int interleave;
  255. int device_type;
  256. int cfi_mode; /* Are we a JEDEC device pretending to be CFI? */
  257. int addr_unlock1;
  258. int addr_unlock2;
  259. int fast_prog;
  260. struct mtd_info *(*cmdset_setup)(struct map_info *);
  261. struct cfi_ident *cfiq; /* For now only one. We insist that all devs
  262.   must be of the same type. */
  263. int mfr, id;
  264. int numchips;
  265. unsigned long chipshift; /* Because they're of the same type */
  266. const char *im_name;  /* inter_module name for cmdset_setup */
  267. struct flchip chips[0];  /* per-chip data structure for each chip */
  268. };
  269. #define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */
  270. /*
  271.  * Returns the command address according to the given geometry.
  272.  */
  273. static inline __u32 cfi_build_cmd_addr(__u32 cmd_ofs, int interleave, int type)
  274. {
  275. return (cmd_ofs * type) * interleave;
  276. }
  277. /*
  278.  * Transforms the CFI command for the given geometry (bus width & interleave.
  279.  */
  280. static inline cfi_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
  281. {
  282. cfi_word val = 0;
  283. if (cfi_buswidth_is_1()) {
  284. /* 1 x8 device */
  285. val = cmd;
  286. } else if (cfi_buswidth_is_2()) {
  287. if (cfi_interleave_is_1()) {
  288. /* 1 x16 device in x16 mode */
  289. val = cpu_to_cfi16(cmd);
  290. } else if (cfi_interleave_is_2()) {
  291. /* 2 (x8, x16 or x32) devices in x8 mode */
  292. val = cpu_to_cfi16((cmd << 8) | cmd);
  293. }
  294. } else if (cfi_buswidth_is_4()) {
  295. if (cfi_interleave_is_1()) {
  296. /* 1 x32 device in x32 mode */
  297. val = cpu_to_cfi32(cmd);
  298. } else if (cfi_interleave_is_2()) {
  299. /* 2 x16 device in x16 mode */
  300. val = cpu_to_cfi32((cmd << 16) | cmd);
  301. } else if (cfi_interleave_is_4()) {
  302. /* 4 (x8, x16 or x32) devices in x8 mode */
  303. val = (cmd << 16) | cmd;
  304. val = cpu_to_cfi32((val << 8) | val);
  305. }
  306. #ifdef CFI_WORD_64
  307. } else if (cfi_buswidth_is_8()) {
  308. if (cfi_interleave_is_1()) {
  309. /* 1 x64 device in x64 mode */
  310. val = cpu_to_cfi64(cmd);
  311. } else if (cfi_interleave_is_2()) {
  312. /* 2 x32 device in x32 mode */
  313. val = cmd;
  314. val = cpu_to_cfi64((val << 32) | val);
  315. } else if (cfi_interleave_is_4()) {
  316. /* 4 (x16, x32 or x64) devices in x16 mode */
  317. val = (cmd << 16) | cmd;
  318. val = cpu_to_cfi64((val << 32) | val);
  319. } else if (cfi_interleave_is_8()) {
  320. /* 8 (x8, x16 or x32) devices in x8 mode */
  321. val = (cmd << 8) | cmd;
  322. val = (val << 16) | val;
  323. val = (val << 32) | val;
  324. val = cpu_to_cfi64(val);
  325. }
  326. #endif /* CFI_WORD_64 */
  327. }
  328. return val;
  329. }
  330. #define CMD(x)  cfi_build_cmd((x), map, cfi)
  331. /*
  332.  * Read a value according to the bus width.
  333.  */
  334. static inline cfi_word cfi_read(struct map_info *map, __u32 addr)
  335. {
  336. if (cfi_buswidth_is_1()) {
  337. return map->read8(map, addr);
  338. } else if (cfi_buswidth_is_2()) {
  339. return map->read16(map, addr);
  340. } else if (cfi_buswidth_is_4()) {
  341. return map->read32(map, addr);
  342. } else if (cfi_buswidth_is_8()) {
  343. return map->read64(map, addr);
  344. } else {
  345. return 0;
  346. }
  347. }
  348. /*
  349.  * Write a value according to the bus width.
  350.  */
  351. static inline void cfi_write(struct map_info *map, cfi_word val, __u32 addr)
  352. {
  353. if (cfi_buswidth_is_1()) {
  354. map->write8(map, val, addr);
  355. } else if (cfi_buswidth_is_2()) {
  356. map->write16(map, val, addr);
  357. } else if (cfi_buswidth_is_4()) {
  358. map->write32(map, val, addr);
  359. } else if (cfi_buswidth_is_8()) {
  360. map->write64(map, val, addr);
  361. }
  362. }
  363. /*
  364.  * Sends a CFI command to a bank of flash for the given geometry.
  365.  *
  366.  * Returns the offset in flash where the command was written.
  367.  * If prev_val is non-null, it will be set to the value at the command address,
  368.  * before the command was written.
  369.  */
  370. static inline __u32 cfi_send_gen_cmd(u_char cmd, __u32 cmd_addr, __u32 base,
  371. struct map_info *map, struct cfi_private *cfi,
  372. int type, cfi_word *prev_val)
  373. {
  374. cfi_word val;
  375. __u32 addr = base + cfi_build_cmd_addr(cmd_addr, CFIDEV_INTERLEAVE, type);
  376. val = cfi_build_cmd(cmd, map, cfi);
  377. if (prev_val)
  378. *prev_val = cfi_read(map, addr);
  379. cfi_write(map, val, addr);
  380. return addr - base;
  381. }
  382. static inline __u8 cfi_read_query(struct map_info *map, __u32 addr)
  383. {
  384. if (cfi_buswidth_is_1()) {
  385. return map->read8(map, addr);
  386. } else if (cfi_buswidth_is_2()) {
  387. return cfi16_to_cpu(map->read16(map, addr));
  388. } else if (cfi_buswidth_is_4()) {
  389. return cfi32_to_cpu(map->read32(map, addr));
  390. } else if (cfi_buswidth_is_8()) {
  391. return cfi64_to_cpu(map->read64(map, addr));
  392. } else {
  393. return 0;
  394. }
  395. }
  396. static inline void cfi_udelay(int us)
  397. {
  398. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
  399. if (current->need_resched) {
  400. unsigned long t = us * HZ / 1000000;
  401. if (t < 1)
  402. t = 1;
  403. set_current_state(TASK_UNINTERRUPTIBLE);
  404. schedule_timeout(t);
  405. }
  406. else
  407. #endif
  408. udelay(us);
  409. }
  410. static inline void cfi_spin_lock(spinlock_t *mutex)
  411. {
  412. spin_lock_bh(mutex);
  413. }
  414. static inline void cfi_spin_unlock(spinlock_t *mutex)
  415. {
  416. spin_unlock_bh(mutex);
  417. }
  418. #endif /* __MTD_CFI_H__ */