[PATCH 12] Fix NOR CFI flash driver to work on big endian systems.

Krzysztof Halasa khc at pm.waw.pl
Mon Dec 20 18:10:41 EST 2010


Fix NOR CFI flash driver to work on big endian systems.
Basically this transforms the u8/u16/u32/u64 union into
a single u64 value.

Not tested on LE platform. Apply with caution.

Signed-off-by: Krzysztof Hałasa <khc at pm.waw.pl>

diff --git a/drivers/nor/cfi_flash.c b/drivers/nor/cfi_flash.c
index 90307d2..34031b0 100644
--- a/drivers/nor/cfi_flash.c
+++ b/drivers/nor/cfi_flash.c
@@ -77,59 +77,40 @@ static uint flash_offset_cfi[2]={FLASH_OFFSET_CFI,FLASH_OFFSET_CFI_ALT};
 
 static void flash_add_byte (struct flash_info *info, cfiword_t * cword, uchar c)
 {
-#if defined(__LITTLE_ENDIAN)
-	unsigned short	w;
-	unsigned int	l;
-	unsigned long long ll;
-#endif
-
 	if (bankwidth_is_1(info)) {
-		cword->c = c;
-	} else if (bankwidth_is_2(info)) {
-#if defined(__LITTLE_ENDIAN)
-		w = c;
-		w <<= 8;
-		cword->w = (cword->w >> 8) | w;
-#else
-		cword->w = (cword->w << 8) | c;
-#endif
-	} else if (bankwidth_is_4(info)) {
-#if defined(__LITTLE_ENDIAN)
-		l = c;
-		l <<= 24;
-		cword->l = (cword->l >> 8) | l;
-#else
-		cword->l = (cword->l << 8) | c;
-#endif
-	} else if (bankwidth_is_8(info)) {
-#if defined(__LITTLE_ENDIAN)
-		ll = c;
-		ll <<= 56;
-		cword->ll = (cword->ll >> 8) | ll;
+		*cword = c;
+		return;
+	}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+	*cword = (*cword << 8) | c;
 #else
-		cword->ll = (cword->ll << 8) | c;
+
+	if (bankwidth_is_2(info))
+		*cword = (*cword >> 8) | (u16)c << 8;
+	else if (bankwidth_is_4(info))
+		*cword = (*cword >> 8) | (u32)c << 24;
+	else if (bankwidth_is_8(info))
+		*cword = (*cword >> 8) | (u64)c << 56;
 #endif
-	}
 }
 
 static int flash_write_cfiword (struct flash_info *info, ulong dest,
 				cfiword_t cword)
 {
-	void *dstaddr;
+	void *dstaddr = (void *)dest;
 	int flag;
 
-	dstaddr = (uchar *) dest;
-
 	/* Check if Flash is (sufficiently) erased */
-	if (bankwidth_is_1(info)) {
-		flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
-	} else if (bankwidth_is_2(info)) {
-		flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
-	} else if (bankwidth_is_4(info)) {
-		flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
-	} else if (bankwidth_is_8(info)) {
-		flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
-	} else
+	if (bankwidth_is_1(info))
+		flag = ((flash_read8(dstaddr) & cword) == cword);
+	else if (bankwidth_is_2(info))
+		flag = ((flash_read16(dstaddr) & cword) == cword);
+	else if (bankwidth_is_4(info))
+		flag = ((flash_read32(dstaddr) & cword) == cword);
+	else if (bankwidth_is_8(info))
+		flag = ((flash_read64(dstaddr) & cword) == cword);
+	else
 		return 2;
 
 	if (!flag)
@@ -185,10 +166,8 @@ static void flash_printqry (struct cfi_qry *qry)
  */
 uchar flash_read_uchar (struct flash_info *info, uint offset)
 {
-	uchar *cp;
-
-	cp = flash_make_addr (info, 0, offset);
-#if defined(__LITTLE_ENDIAN)
+	uchar *cp = flash_make_addr(info, 0, offset);
+#if __BYTE_ORDER == __LITTLE_ENDIAN
 	return flash_read8(cp);
 #else
 	return flash_read8(cp + info->portwidth - 1);
@@ -216,7 +195,7 @@ static ulong flash_read_long (struct flash_info *info, flash_sect_t sect, uint o
 		debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
 	}
 #endif
-#if defined(__LITTLE_ENDIAN)
+#if __BYTE_ORDER == __LITTLE_ENDIAN
 	retval = ((flash_read8(addr) << 16) |
 		  (flash_read8(addr + info->portwidth) << 24) |
 		  (flash_read8(addr + 2 * info->portwidth)) |
@@ -534,7 +513,7 @@ static int write_buff (struct flash_info *info, const uchar * src, ulong addr, u
 
 	/* handle unaligned start */
 	if ((aln = addr - wp) != 0) {
-		cword.l = 0;
+		cword = 0;
 		p = (uchar*)wp;
 		for (i = 0; i < aln; ++i)
 			flash_add_byte (info, &cword, flash_read8(p + i));
@@ -560,7 +539,7 @@ static int write_buff (struct flash_info *info, const uchar * src, ulong addr, u
 	while (cnt >= info->portwidth) {
 		/* prohibit buffer write when buffer_size is 1 */
 		if (info->buffer_size == 1) {
-			cword.l = 0;
+			cword = 0;
 			for (i = 0; i < info->portwidth; i++)
 				flash_add_byte (info, &cword, *src++);
 			if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
@@ -583,7 +562,7 @@ static int write_buff (struct flash_info *info, const uchar * src, ulong addr, u
 	}
 #else
 	while (cnt >= info->portwidth) {
-		cword.l = 0;
+		cword = 0;
 		for (i = 0; i < info->portwidth; i++) {
 			flash_add_byte (info, &cword, *src++);
 		}
@@ -600,7 +579,7 @@ static int write_buff (struct flash_info *info, const uchar * src, ulong addr, u
 	/*
 	 * handle unaligned tail bytes
 	 */
-	cword.l = 0;
+	cword = 0;
 	p = (uchar*)wp;
 	for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
 		flash_add_byte (info, &cword, *src++);
@@ -672,7 +651,7 @@ static ssize_t cfi_write(struct cdev *cdev, const void *buf, size_t count, unsig
         struct flash_info *finfo = (struct flash_info *)cdev->priv;
         int ret;
 
-	debug("cfi_write: buf=0x%08x addr=0x%08x count=0x%08x\n",buf, cdev->dev->map_base + offset, count);
+	debug("cfi_write: buf=0x%p addr=0x%08lx count=0x%08x\n",buf, cdev->dev->map_base + offset, count);
 
         ret = write_buff (finfo, buf, cdev->dev->map_base + offset, count);
         return ret == 0 ? count : -1;
@@ -836,17 +815,14 @@ int flash_generic_status_check (struct flash_info *info, flash_sect_t sector,
 /*
  * make a proper sized command based on the port and chip widths
  */
-void flash_make_cmd (struct flash_info *info, uchar cmd, void *cmdbuf)
+void flash_make_cmd(struct flash_info *info, u8 cmd, cfiword_t *cmdbuf)
 {
-	int i;
-	uchar *cp = (uchar *) cmdbuf;
+	cfiword_t result = 0;
+	int i = info->portwidth / info->chipwidth;
 
-#if defined(__LITTLE_ENDIAN)
-	for (i = info->portwidth; i > 0; i--)
-#else
-	for (i = 1; i <= info->portwidth; i++)
-#endif
-		*cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd;
+	while (i--)
+		result = (result << (8 * info->chipwidth)) | cmd;
+	*cmdbuf = result;
 }
 
 /*
@@ -860,6 +836,7 @@ void flash_write_cmd (struct flash_info *info, flash_sect_t sect, uint offset, u
 
 	addr = flash_make_addr (info, sect, offset);
 	flash_make_cmd (info, cmd, &cword);
+	debug("%s: %p %lX %X => %p %llX\n", __FUNCTION__, info, sect, offset, addr, cword);
 	flash_write_word(info, cword, addr);
 }
 
@@ -874,14 +851,14 @@ int flash_isequal (struct flash_info *info, flash_sect_t sect, uint offset, ucha
 
 	debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
 	if (bankwidth_is_1(info)) {
-		debug ("is= %x %x\n", flash_read8(addr), cword.c);
-		retval = (flash_read8(addr) == cword.c);
+		debug ("is= %x %x\n", flash_read8(addr), (u8)cword);
+		retval = (flash_read8(addr) == cword);
 	} else if (bankwidth_is_2(info)) {
-		debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
-		retval = (flash_read16(addr) == cword.w);
+		debug ("is= %4.4x %4.4x\n", flash_read16(addr), (u16)cword);
+		retval = (flash_read16(addr) == cword);
 	} else if (bankwidth_is_4(info)) {
-		debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l);
-		retval = (flash_read32(addr) == cword.l);
+		debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), (u32)cword);
+		retval = (flash_read32(addr) == cword);
 	} else if (bankwidth_is_8(info)) {
 #ifdef DEBUG
 		{
@@ -889,11 +866,11 @@ int flash_isequal (struct flash_info *info, flash_sect_t sect, uint offset, ucha
 			char str2[20];
 
 			print_longlong (str1, flash_read32(addr));
-			print_longlong (str2, cword.ll);
+			print_longlong (str2, cword);
 			debug ("is= %s %s\n", str1, str2);
 		}
 #endif
-		retval = (flash_read32(addr) == cword.ll);
+		retval = (flash_read64(addr) == cword);
 	} else
 		retval = 0;
 
@@ -902,20 +879,19 @@ int flash_isequal (struct flash_info *info, flash_sect_t sect, uint offset, ucha
 
 int flash_isset (struct flash_info *info, flash_sect_t sect, uint offset, uchar cmd)
 {
-	void *addr;
+	void *addr = flash_make_addr (info, sect, offset);
 	cfiword_t cword;
 	int retval;
 
-	addr = flash_make_addr (info, sect, offset);
 	flash_make_cmd (info, cmd, &cword);
 	if (bankwidth_is_1(info)) {
-		retval = ((flash_read8(addr) & cword.c) == cword.c);
+		retval = ((flash_read8(addr) & cword) == cword);
 	} else if (bankwidth_is_2(info)) {
-		retval = ((flash_read16(addr) & cword.w) == cword.w);
+		retval = ((flash_read16(addr) & cword) == cword);
 	} else if (bankwidth_is_4(info)) {
-		retval = ((flash_read32(addr) & cword.l) == cword.l);
+		retval = ((flash_read32(addr) & cword) == cword);
 	} else if (bankwidth_is_8(info)) {
-		retval = ((flash_read64(addr) & cword.ll) == cword.ll);
+		retval = ((flash_read64(addr) & cword) == cword);
 	} else
 		retval = 0;
 
@@ -1001,6 +977,7 @@ static int cfi_probe (struct device_d *dev)
 
 	/* Init: no FLASHes known */
 	info->flash_id = FLASH_UNKNOWN;
+	info->cmd_reset = FLASH_CMD_RESET;
 	info->size = flash_get_size(info, dev->map_base);
 	info->base = (void __iomem *)dev->map_base;
 
diff --git a/drivers/nor/cfi_flash.h b/drivers/nor/cfi_flash.h
index f9023dc..9098021 100644
--- a/drivers/nor/cfi_flash.h
+++ b/drivers/nor/cfi_flash.h
@@ -25,10 +25,12 @@
  */
 
 #include <driver.h>
+#include <asm/byteorder.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 
 typedef unsigned long flash_sect_t;
+typedef u64 cfiword_t;
 struct cfi_cmd_set;
 
 /*-----------------------------------------------------------------------
@@ -238,7 +240,7 @@ int flash_generic_status_check (struct flash_info *info, flash_sect_t sector,
 			       uint64_t tout, char *prompt);
 
 int flash_isequal (struct flash_info *info, flash_sect_t sect, uint offset, uchar cmd);
-void flash_make_cmd (struct flash_info *info, uchar cmd, void *cmdbuf);
+void flash_make_cmd(struct flash_info *info, uchar cmd, cfiword_t *cmdbuf);
 
 static inline void flash_write8(u8 value, void *addr)
 {
@@ -316,26 +318,19 @@ u32 jedec_read_mfr(struct flash_info *info);
 #define bankwidth_is_8(info) 0
 #endif
 
-typedef union {
-	unsigned char c;
-	unsigned short w;
-	unsigned long l;
-	unsigned long long ll;
-} cfiword_t;
-
 static inline void flash_write_word(struct flash_info *info, cfiword_t datum, void *addr)
 {
 	if (bankwidth_is_1(info)) {
-		debug("fw addr %p val %02x\n", addr, datum.c);
-		flash_write8(datum.c, addr);
+		debug("fw addr %p val %02x\n", addr, (u8)datum);
+		flash_write8(datum, addr);
 	} else if (bankwidth_is_2(info)) {
-		debug("fw addr %p val %04x\n", addr, datum.w);
-		flash_write16(datum.w, addr);
+		debug("fw addr %p val %04x\n", addr, (u16)datum);
+		flash_write16(datum, addr);
 	} else if (bankwidth_is_4(info)) {
-		debug("fw addr %p val %08x\n", addr, datum.l);
-		flash_write32(datum.l, addr);
+		debug("fw addr %p val %08x\n", addr, (u32)datum);
+		flash_write32(datum, addr);
 	} else if (bankwidth_is_8(info)) {
-		flash_write64(datum.ll, addr);
+		flash_write64(datum, addr);
 	}
 }
 



More information about the barebox mailing list