cfi.h
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:10k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* Common Flash Interface structures 
  2.  * See http://support.intel.com/design/flash/technote/index.htm
  3.  * $Id: cfi.h,v 1.25 2001/09/04 07:06:21 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 or 4 bytes)
  18.  *
  19.  * By default, all (known) geometries are supported.
  20.  */
  21. #ifndef CONFIG_MTD_CFI_GEOMETRY
  22. #define CFIDEV_INTERLEAVE_1 (1)
  23. #define CFIDEV_INTERLEAVE_2 (2)
  24. #define CFIDEV_INTERLEAVE_4 (4)
  25. #define CFIDEV_BUSWIDTH_1 (1)
  26. #define CFIDEV_BUSWIDTH_2 (2)
  27. #define CFIDEV_BUSWIDTH_4 (4)
  28. #else
  29. #ifdef CONFIG_MTD_CFI_I1
  30. #define CFIDEV_INTERLEAVE_1 (1)
  31. #endif
  32. #ifdef CONFIG_MTD_CFI_I2
  33. #define CFIDEV_INTERLEAVE_2 (2)
  34. #endif
  35. #ifdef CONFIG_MTD_CFI_I4
  36. #define CFIDEV_INTERLEAVE_4 (4)
  37. #endif
  38. #ifdef CONFIG_MTD_CFI_B1
  39. #define CFIDEV_BUSWIDTH_1 (1)
  40. #endif
  41. #ifdef CONFIG_MTD_CFI_B2
  42. #define CFIDEV_BUSWIDTH_2 (2)
  43. #endif
  44. #ifdef CONFIG_MTD_CFI_B4
  45. #define CFIDEV_BUSWIDTH_4 (4)
  46. #endif
  47. #endif
  48. /*
  49.  * The following macros are used to select the code to execute:
  50.  *   cfi_buswidth_is_*()
  51.  *   cfi_interleave_is_*()
  52.  *   [where * is either 1, 2 or 4]
  53.  * Those macros should be used with 'if' statements.  If only one of few
  54.  * geometry arrangements are selected, they expand to constants thus allowing
  55.  * the compiler (most of them being 0) to optimize away all the unneeded code,
  56.  * while still validating the syntax (which is not possible with embedded 
  57.  * #if ... #endif constructs).
  58.  */
  59. #ifdef CFIDEV_INTERLEAVE_1
  60. # ifdef CFIDEV_INTERLEAVE
  61. #  undef CFIDEV_INTERLEAVE
  62. #  define CFIDEV_INTERLEAVE (cfi->interleave)
  63. # else
  64. #  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_1
  65. # endif
  66. # define cfi_interleave_is_1() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_1)
  67. #else
  68. # define cfi_interleave_is_1() (0)
  69. #endif
  70. #ifdef CFIDEV_INTERLEAVE_2
  71. # ifdef CFIDEV_INTERLEAVE
  72. #  undef CFIDEV_INTERLEAVE
  73. #  define CFIDEV_INTERLEAVE (cfi->interleave)
  74. # else
  75. #  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_2
  76. # endif
  77. # define cfi_interleave_is_2() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_2)
  78. #else
  79. # define cfi_interleave_is_2() (0)
  80. #endif
  81. #ifdef CFIDEV_INTERLEAVE_4
  82. # ifdef CFIDEV_INTERLEAVE
  83. #  undef CFIDEV_INTERLEAVE
  84. #  define CFIDEV_INTERLEAVE (cfi->interleave)
  85. # else
  86. #  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_4
  87. # endif
  88. # define cfi_interleave_is_4() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_4)
  89. #else
  90. # define cfi_interleave_is_4() (0)
  91. #endif
  92. #ifndef CFIDEV_INTERLEAVE
  93. #error You must define at least one interleave to support!
  94. #endif
  95. #ifdef CFIDEV_BUSWIDTH_1
  96. # ifdef CFIDEV_BUSWIDTH
  97. #  undef CFIDEV_BUSWIDTH
  98. #  define CFIDEV_BUSWIDTH (map->buswidth)
  99. # else
  100. #  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_1
  101. # endif
  102. # define cfi_buswidth_is_1() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_1)
  103. #else
  104. # define cfi_buswidth_is_1() (0)
  105. #endif
  106. #ifdef CFIDEV_BUSWIDTH_2
  107. # ifdef CFIDEV_BUSWIDTH
  108. #  undef CFIDEV_BUSWIDTH
  109. #  define CFIDEV_BUSWIDTH (map->buswidth)
  110. # else
  111. #  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_2
  112. # endif
  113. # define cfi_buswidth_is_2() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_2)
  114. #else
  115. # define cfi_buswidth_is_2() (0)
  116. #endif
  117. #ifdef CFIDEV_BUSWIDTH_4
  118. # ifdef CFIDEV_BUSWIDTH
  119. #  undef CFIDEV_BUSWIDTH
  120. #  define CFIDEV_BUSWIDTH (map->buswidth)
  121. # else
  122. #  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_4
  123. # endif
  124. # define cfi_buswidth_is_4() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_4)
  125. #else
  126. # define cfi_buswidth_is_4() (0)
  127. #endif
  128. #ifndef CFIDEV_BUSWIDTH
  129. #error You must define at least one bus width to support!
  130. #endif
  131. /* NB: these values must represents the number of bytes needed to meet the 
  132.  *     device type (x8, x16, x32).  Eg. a 32 bit device is 4 x 8 bytes. 
  133.  *     These numbers are used in calculations.
  134.  */
  135. #define CFI_DEVICETYPE_X8  (8 / 8)
  136. #define CFI_DEVICETYPE_X16 (16 / 8)
  137. #define CFI_DEVICETYPE_X32 (32 / 8)
  138. /* NB: We keep these structures in memory in HOST byteorder, except
  139.  * where individually noted.
  140.  */
  141. /* Basic Query Structure */
  142. struct cfi_ident {
  143.   __u8  qry[3];
  144.   __u16 P_ID;
  145.   __u16 P_ADR;
  146.   __u16 A_ID;
  147.   __u16 A_ADR;
  148.   __u8  VccMin;
  149.   __u8  VccMax;
  150.   __u8  VppMin;
  151.   __u8  VppMax;
  152.   __u8  WordWriteTimeoutTyp;
  153.   __u8  BufWriteTimeoutTyp;
  154.   __u8  BlockEraseTimeoutTyp;
  155.   __u8  ChipEraseTimeoutTyp;
  156.   __u8  WordWriteTimeoutMax;
  157.   __u8  BufWriteTimeoutMax;
  158.   __u8  BlockEraseTimeoutMax;
  159.   __u8  ChipEraseTimeoutMax;
  160.   __u8  DevSize;
  161.   __u16 InterfaceDesc;
  162.   __u16 MaxBufWriteSize;
  163.   __u8  NumEraseRegions;
  164.   __u32 EraseRegionInfo[0]; /* Not host ordered */
  165. } __attribute__((packed));
  166. /* Extended Query Structure for both PRI and ALT */
  167. struct cfi_extquery {
  168.   __u8  pri[3];
  169.   __u8  MajorVersion;
  170.   __u8  MinorVersion;
  171. } __attribute__((packed));
  172. /* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */
  173. struct cfi_pri_intelext {
  174.   __u8  pri[3];
  175.   __u8  MajorVersion;
  176.   __u8  MinorVersion;
  177.   __u32 FeatureSupport;
  178.   __u8  SuspendCmdSupport;
  179.   __u16 BlkStatusRegMask;
  180.   __u8  VccOptimal;
  181.   __u8  VppOptimal;
  182. } __attribute__((packed));
  183. struct cfi_pri_query {
  184.   __u8  NumFields;
  185.   __u32 ProtField[1]; /* Not host ordered */
  186. } __attribute__((packed));
  187. struct cfi_bri_query {
  188.   __u8  PageModeReadCap;
  189.   __u8  NumFields;
  190.   __u32 ConfField[1]; /* Not host ordered */
  191. } __attribute__((packed));
  192. #define P_ID_NONE 0
  193. #define P_ID_INTEL_EXT 1
  194. #define P_ID_AMD_STD 2
  195. #define P_ID_INTEL_STD 3
  196. #define P_ID_AMD_EXT 4
  197. #define P_ID_MITSUBISHI_STD 256
  198. #define P_ID_MITSUBISHI_EXT 257
  199. #define P_ID_RESERVED 65535
  200. #define CFI_MODE_CFI 0
  201. #define CFI_MODE_JEDEC 1
  202. struct cfi_private {
  203. __u16 cmdset;
  204. void *cmdset_priv;
  205. int interleave;
  206. int device_type;
  207. int cfi_mode; /* Are we a JEDEC device pretending to be CFI? */
  208. int addr_unlock1;
  209. int addr_unlock2;
  210. int fast_prog;
  211. struct mtd_info *(*cmdset_setup)(struct map_info *);
  212. struct cfi_ident *cfiq; /* For now only one. We insist that all devs
  213.   must be of the same type. */
  214. int mfr, id;
  215. int numchips;
  216. unsigned long chipshift; /* Because they're of the same type */
  217. const char *im_name;  /* inter_module name for cmdset_setup */
  218. struct flchip chips[0];  /* per-chip data structure for each chip */
  219. };
  220. #define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */
  221. /*
  222.  * Returns the command address according to the given geometry.
  223.  */
  224. static inline __u32 cfi_build_cmd_addr(__u32 cmd_ofs, int interleave, int type)
  225. {
  226. return (cmd_ofs * type) * interleave;
  227. }
  228. /*
  229.  * Transforms the CFI command for the given geometry (bus width & interleave.
  230.  */
  231. static inline __u32 cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
  232. {
  233. __u32 val = 0;
  234. if (cfi_buswidth_is_1()) {
  235. /* 1 x8 device */
  236. val = cmd;
  237. } else if (cfi_buswidth_is_2()) {
  238. if (cfi_interleave_is_1()) {
  239. /* 1 x16 device in x16 mode */
  240. val = cpu_to_cfi16(cmd);
  241. } else if (cfi_interleave_is_2()) {
  242. /* 2 (x8, x16 or x32) devices in x8 mode */
  243. val = cpu_to_cfi16((cmd << 8) | cmd);
  244. }
  245. } else if (cfi_buswidth_is_4()) {
  246. if (cfi_interleave_is_1()) {
  247. /* 1 x32 device in x32 mode */
  248. val = cpu_to_cfi32(cmd);
  249. } else if (cfi_interleave_is_2()) {
  250. /* 2 x16 device in x16 mode */
  251. val = cpu_to_cfi32((cmd << 16) | cmd);
  252. } else if (cfi_interleave_is_4()) {
  253. /* 4 (x8, x16 or x32) devices in x8 mode */
  254. val = (cmd << 16) | cmd;
  255. val = cpu_to_cfi32((val << 8) | val);
  256. }
  257. }
  258. return val;
  259. }
  260. #define CMD(x)  cfi_build_cmd((x), map, cfi)
  261. /*
  262.  * Read a value according to the bus width.
  263.  */
  264. static inline __u32 cfi_read(struct map_info *map, __u32 addr)
  265. {
  266. if (cfi_buswidth_is_1()) {
  267. return map->read8(map, addr);
  268. } else if (cfi_buswidth_is_2()) {
  269. return map->read16(map, addr);
  270. } else if (cfi_buswidth_is_4()) {
  271. return map->read32(map, addr);
  272. } else {
  273. return 0;
  274. }
  275. }
  276. /*
  277.  * Write a value according to the bus width.
  278.  */
  279. static inline void cfi_write(struct map_info *map, __u32 val, __u32 addr)
  280. {
  281. if (cfi_buswidth_is_1()) {
  282. map->write8(map, val, addr);
  283. } else if (cfi_buswidth_is_2()) {
  284. map->write16(map, val, addr);
  285. } else if (cfi_buswidth_is_4()) {
  286. map->write32(map, val, addr);
  287. }
  288. }
  289. /*
  290.  * Sends a CFI command to a bank of flash for the given geometry.
  291.  *
  292.  * Returns the offset in flash where the command was written.
  293.  * If prev_val is non-null, it will be set to the value at the command address,
  294.  * before the command was written.
  295.  */
  296. static inline __u32 cfi_send_gen_cmd(u_char cmd, __u32 cmd_addr, __u32 base,
  297. struct map_info *map, struct cfi_private *cfi,
  298. int type, __u32 *prev_val)
  299. {
  300. __u32 val;
  301. __u32 addr = base + cfi_build_cmd_addr(cmd_addr, CFIDEV_INTERLEAVE, type);
  302. val = cfi_build_cmd(cmd, map, cfi);
  303. if (prev_val)
  304. *prev_val = cfi_read(map, addr);
  305. cfi_write(map, val, addr);
  306. return addr - base;
  307. }
  308. static inline __u8 cfi_read_query(struct map_info *map, __u32 addr)
  309. {
  310. if (cfi_buswidth_is_1()) {
  311. return map->read8(map, addr);
  312. } else if (cfi_buswidth_is_2()) {
  313. return cfi16_to_cpu(map->read16(map, addr));
  314. } else if (cfi_buswidth_is_4()) {
  315. return cfi32_to_cpu(map->read32(map, addr));
  316. } else {
  317. return 0;
  318. }
  319. }
  320. static inline void cfi_udelay(int us)
  321. {
  322. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
  323. if (current->need_resched) {
  324. unsigned long t = us * HZ / 1000000;
  325. if (t < 1)
  326. t = 1;
  327. set_current_state(TASK_UNINTERRUPTIBLE);
  328. schedule_timeout(t);
  329. }
  330. else
  331. #endif
  332. udelay(us);
  333. }
  334. static inline void cfi_spin_lock(spinlock_t *mutex)
  335. {
  336. spin_lock_bh(mutex);
  337. }
  338. static inline void cfi_spin_unlock(spinlock_t *mutex)
  339. {
  340. spin_unlock_bh(mutex);
  341. }
  342. #endif /* __MTD_CFI_H__ */