patch for 64 bit wide flash

Adam Wozniak adam.wozniak at comdev.cc
Thu Dec 27 18:31:30 EST 2001


David Woodhouse wrote:
> 
> adam.wozniak at comdev.cc said:
> > I've got a 64 bit wide flash consisting of eight 8bit wide chips.
> > Here's a patch against the 2.4.16 kernel
> 
> I'm a little concerned about the following bit - gcc is fairly crap at
> dealing with 64-bit datatypes. I'd prefer to do that only if it's
> necessary. Can we define a cfi_busword type which is only as big as we need
> - so it's only a __u64 if CONFIG_MTD_CFI_B8 is set?

Here's a new patch.

cfi.h has the following in it (paraphrased and indented for readablity):

#ifndef CONFIG_MTD_CFI_GEOMETRY
 
/* we don't know what we'll get, so we pick the largest possible here */
typedef __u64 cfi_word;
 
#else

/* pick the largest necessary */
#ifdef CONFIG_MTD_CFI_B8
typedef __u64 cfi_word;
#else  /* CONFIG_MTD_CFI_B8 */
   #ifdef CONFIG_MTD_CFI_B4
   typedef __u32 cfi_word;
   #else  /* CONFIG_MTD_CFI_B4 */
      #ifdef CONFIG_MTD_CFI_B2
      typedef __u16 cfi_word;
      #else  /* CONFIG_MTD_CFI_B2 */
         #ifdef CONFIG_MTD_CFI_B1
         typedef __u8 cfi_word;
         #else  /* CONFIG_MTD_CFI_B1 */
            #error You must specify a bus width
         #endif /* CONFIG_MTD_CFI_B1 */
      #endif /* CONFIG_MTD_CFI_B2 */
   #endif /* CONFIG_MTD_CFI_B4 */
#endif /* CONFIG_MTD_CFI_B8 */
 
#endif

-- 
Adam Wozniak (KG6GZR)   COM DEV Wireless - Digital and Software Systems
awozniak at comdev.cc      3450 Broad St. 107, San Luis Obispo, CA 93401
                        http://www.comdev.cc
                        Voice: (805) 544-1089       Fax: (805) 544-2055
-------------- next part --------------
diff -urbBN --exclude=autoconf.h --exclude=compile.h --exclude=version.h --exclude=config --exclude=asm --exclude=asm-ppc --exclude=.*depend --exclude=*.flags --exclude=*.o linux-original/include/linux/mtd/cfi.h linux/include/linux/mtd/cfi.h
--- linux-original/include/linux/mtd/cfi.h	Thu Oct  4 15:13:18 2001
+++ linux/include/linux/mtd/cfi.h	Thu Dec 27 15:21:09 2001
@@ -28,10 +28,15 @@
 #define CFIDEV_INTERLEAVE_1 (1)
 #define CFIDEV_INTERLEAVE_2 (2)
 #define CFIDEV_INTERLEAVE_4 (4)
+#define CFIDEV_INTERLEAVE_8 (8)
 
 #define CFIDEV_BUSWIDTH_1 (1)
 #define CFIDEV_BUSWIDTH_2 (2)
 #define CFIDEV_BUSWIDTH_4 (4)
+#define CFIDEV_BUSWIDTH_8 (8)
+
+/* we don't know what we'll get, so we pick the largest possible here */
+typedef __u64 cfi_word;
 
 #else
 
@@ -44,6 +49,9 @@
 #ifdef CONFIG_MTD_CFI_I4
 #define CFIDEV_INTERLEAVE_4 (4)
 #endif
+#ifdef CONFIG_MTD_CFI_I8
+#define CFIDEV_INTERLEAVE_8 (8)
+#endif
 
 #ifdef CONFIG_MTD_CFI_B1
 #define CFIDEV_BUSWIDTH_1 (1)
@@ -54,6 +62,28 @@
 #ifdef CONFIG_MTD_CFI_B4
 #define CFIDEV_BUSWIDTH_4 (4)
 #endif
+#ifdef CONFIG_MTD_CFI_B8
+#define CFIDEV_BUSWIDTH_8 (8)
+#endif
+
+/* pick the largest necessary */
+#ifdef CONFIG_MTD_CFI_B8
+typedef __u64 cfi_word;
+#else  /* CONFIG_MTD_CFI_B8 */
+#ifdef CONFIG_MTD_CFI_B4
+typedef __u32 cfi_word;
+#else  /* CONFIG_MTD_CFI_B4 */
+#ifdef CONFIG_MTD_CFI_B2
+typedef __u16 cfi_word;
+#else  /* CONFIG_MTD_CFI_B2 */
+#ifdef CONFIG_MTD_CFI_B1
+typedef __u8 cfi_word;
+#else  /* CONFIG_MTD_CFI_B1 */
+#error You must specify a bus width
+#endif /* CONFIG_MTD_CFI_B1 */
+#endif /* CONFIG_MTD_CFI_B2 */
+#endif /* CONFIG_MTD_CFI_B4 */
+#endif /* CONFIG_MTD_CFI_B8 */
 
 #endif
 
@@ -61,7 +91,7 @@
  * The following macros are used to select the code to execute:
  *   cfi_buswidth_is_*()
  *   cfi_interleave_is_*()
- *   [where * is either 1, 2 or 4]
+ *   [where * is either 1, 2, 4, or 8]
  * Those macros should be used with 'if' statements.  If only one of few
  * geometry arrangements are selected, they expand to constants thus allowing
  * the compiler (most of them being 0) to optimize away all the unneeded code,
@@ -105,6 +135,18 @@
 # define cfi_interleave_is_4() (0)
 #endif
 
+#ifdef CFIDEV_INTERLEAVE_8
+# ifdef CFIDEV_INTERLEAVE
+#  undef CFIDEV_INTERLEAVE
+#  define CFIDEV_INTERLEAVE (cfi->interleave)
+# else
+#  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_8
+# endif
+# define cfi_interleave_is_8() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_8)
+#else
+# define cfi_interleave_is_8() (0)
+#endif
+
 #ifndef CFIDEV_INTERLEAVE
 #error You must define at least one interleave to support!
 #endif
@@ -145,6 +187,18 @@
 # define cfi_buswidth_is_4() (0)
 #endif
 
+#ifdef CFIDEV_BUSWIDTH_8
+# ifdef CFIDEV_BUSWIDTH
+#  undef CFIDEV_BUSWIDTH
+#  define CFIDEV_BUSWIDTH (map->buswidth)
+# else
+#  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_8
+# endif
+# define cfi_buswidth_is_8() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_8)
+#else
+# define cfi_buswidth_is_8() (0)
+#endif
+
 #ifndef CFIDEV_BUSWIDTH
 #error You must define at least one bus width to support!
 #endif
@@ -156,6 +210,7 @@
 #define CFI_DEVICETYPE_X8  (8 / 8)
 #define CFI_DEVICETYPE_X16 (16 / 8)
 #define CFI_DEVICETYPE_X32 (32 / 8)
+#define CFI_DEVICETYPE_X64 (64 / 8)
 
 /* NB: We keep these structures in memory in HOST byteorder, except
  * where individually noted.
@@ -264,9 +319,9 @@
 /*
  * Transforms the CFI command for the given geometry (bus width & interleave.
  */
-static inline __u32 cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
+static inline cfi_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
 {
-	__u32 val = 0;
+	cfi_word val = 0;
 
 	if (cfi_buswidth_is_1()) {
 		/* 1 x8 device */
@@ -291,6 +346,25 @@
 			val = (cmd << 16) | cmd;
 			val = cpu_to_cfi32((val << 8) | val);
 		}
+	} else if (cfi_buswidth_is_8()) {
+		if (cfi_interleave_is_1()) {
+			/* 1 x64 device in x64 mode */
+			val = cpu_to_cfi64(cmd);
+		} else if (cfi_interleave_is_2()) {
+			/* 2 x32 device in x32 mode */
+			val = cmd;
+			val = cpu_to_cfi64((val << 32) | val);
+		} else if (cfi_interleave_is_4()) {
+			/* 4 (x16, x32 or x64) devices in x16 mode */
+			val = (cmd << 16) | cmd;
+			val = cpu_to_cfi64((val << 32) | val);
+		} else if (cfi_interleave_is_8()) {
+			/* 8 (x8, x16 or x32) devices in x8 mode */
+			val = (cmd << 8) | cmd;
+			val = (val << 16) | val;
+			val = (val << 32) | val;
+			val = cpu_to_cfi64(val);
+		}
 	}
 	return val;
 }
@@ -300,7 +374,7 @@
  * Read a value according to the bus width.
  */
 
-static inline __u32 cfi_read(struct map_info *map, __u32 addr)
+static inline cfi_word cfi_read(struct map_info *map, __u32 addr)
 {
 	if (cfi_buswidth_is_1()) {
 		return map->read8(map, addr);
@@ -308,6 +382,8 @@
 		return map->read16(map, addr);
 	} else if (cfi_buswidth_is_4()) {
 		return map->read32(map, addr);
+	} else if (cfi_buswidth_is_8()) {
+		return map->read64(map, addr);
 	} else {
 		return 0;
 	}
@@ -317,7 +393,7 @@
  * Write a value according to the bus width.
  */
 
-static inline void cfi_write(struct map_info *map, __u32 val, __u32 addr)
+static inline void cfi_write(struct map_info *map, cfi_word val, __u32 addr)
 {
 	if (cfi_buswidth_is_1()) {
 		map->write8(map, val, addr);
@@ -325,6 +401,8 @@
 		map->write16(map, val, addr);
 	} else if (cfi_buswidth_is_4()) {
 		map->write32(map, val, addr);
+	} else if (cfi_buswidth_is_8()) {
+		map->write64(map, val, addr);
 	}
 }
 
@@ -337,9 +415,9 @@
  */
 static inline __u32 cfi_send_gen_cmd(u_char cmd, __u32 cmd_addr, __u32 base,
 				struct map_info *map, struct cfi_private *cfi,
-				int type, __u32 *prev_val)
+				int type, cfi_word *prev_val)
 {
-	__u32 val;
+	cfi_word val;
 	__u32 addr = base + cfi_build_cmd_addr(cmd_addr, CFIDEV_INTERLEAVE, type);
 
 	val = cfi_build_cmd(cmd, map, cfi);
@@ -360,6 +438,8 @@
 		return cfi16_to_cpu(map->read16(map, addr));
 	} else if (cfi_buswidth_is_4()) {
 		return cfi32_to_cpu(map->read32(map, addr));
+	} else if (cfi_buswidth_is_8()) {
+		return cfi64_to_cpu(map->read64(map, addr));
 	} else {
 		return 0;
 	}
diff -urbBN --exclude=autoconf.h --exclude=compile.h --exclude=version.h --exclude=config --exclude=asm --exclude=asm-ppc --exclude=.*depend --exclude=*.flags --exclude=*.o linux-original/include/linux/mtd/cfi_endian.h linux/include/linux/mtd/cfi_endian.h
--- linux-original/include/linux/mtd/cfi_endian.h	Thu Oct  4 15:13:18 2001
+++ linux/include/linux/mtd/cfi_endian.h	Wed Dec 19 11:52:03 2001
@@ -30,22 +30,28 @@
 #define cfi8_to_cpu(x) (x)
 #define cpu_to_cfi16(x) cpu_to_le16(x)
 #define cpu_to_cfi32(x) cpu_to_le32(x)
+#define cpu_to_cfi64(x) cpu_to_le64(x)
 #define cfi16_to_cpu(x) le16_to_cpu(x)
 #define cfi32_to_cpu(x) le32_to_cpu(x)
+#define cfi64_to_cpu(x) le64_to_cpu(x)
 #elif defined (CFI_BIG_ENDIAN)
 #define cpu_to_cfi8(x) (x)
 #define cfi8_to_cpu(x) (x)
 #define cpu_to_cfi16(x) cpu_to_be16(x)
 #define cpu_to_cfi32(x) cpu_to_be32(x)
+#define cpu_to_cfi64(x) cpu_to_be64(x)
 #define cfi16_to_cpu(x) be16_to_cpu(x)
 #define cfi32_to_cpu(x) be32_to_cpu(x)
+#define cfi64_to_cpu(x) be64_to_cpu(x)
 #elif defined (CFI_HOST_ENDIAN)
 #define cpu_to_cfi8(x) (x)
 #define cfi8_to_cpu(x) (x)
 #define cpu_to_cfi16(x) (x)
 #define cpu_to_cfi32(x) (x)
+#define cpu_to_cfi64(x) (x)
 #define cfi16_to_cpu(x) (x)
 #define cfi32_to_cpu(x) (x)
+#define cfi64_to_cpu(x) (x)
 #else
 #error No CFI endianness defined
 #endif
diff -urbBN --exclude=autoconf.h --exclude=compile.h --exclude=version.h --exclude=config --exclude=asm --exclude=asm-ppc --exclude=.*depend --exclude=*.flags --exclude=*.o linux-original/include/linux/mtd/map.h linux/include/linux/mtd/map.h
--- linux-original/include/linux/mtd/map.h	Thu Oct  4 15:13:18 2001
+++ linux/include/linux/mtd/map.h	Wed Dec 19 11:52:03 2001
@@ -33,6 +33,7 @@
 	__u8 (*read8)(struct map_info *, unsigned long);
 	__u16 (*read16)(struct map_info *, unsigned long);
 	__u32 (*read32)(struct map_info *, unsigned long);  
+	__u64 (*read64)(struct map_info *, unsigned long);  
 	/* If it returned a 'long' I'd call it readl.
 	 * It doesn't.
 	 * I won't.
@@ -42,6 +43,7 @@
 	void (*write8)(struct map_info *, __u8, unsigned long);
 	void (*write16)(struct map_info *, __u16, unsigned long);
 	void (*write32)(struct map_info *, __u32, unsigned long);
+	void (*write64)(struct map_info *, __u64, unsigned long);
 	void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t);
 
 	void (*set_vpp)(struct map_info *, int);


More information about the linux-mtd mailing list