Add support for dataflash to U-boot environment settings tool.

* The sector size for SPI-dataflash (like AT45 flashes) are not always
  a power-of-2. So, the sector calculations are rewritten such that it
  works for either power-of-2 as any size sectors.
* Make the flash sector size optional in case it is the same value as
  the environment size.

Signed-off-by: Remy Bohmer <linux@bohmer.net>
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 8ff7052..e0f46bc 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -674,11 +674,7 @@
 				   MEMGETBADBLOCK needs 64 bits */
 	int rc;
 
-	/*
-	 * Start of the first block to be read, relies on the fact, that
-	 * erase sector size is always a power of 2
-	 */
-	blockstart = offset & ~(DEVESIZE (dev) - 1);
+	blockstart = (offset / DEVESIZE (dev)) * DEVESIZE (dev);
 
 	/* Offset inside a block */
 	block_seek = offset - blockstart;
@@ -694,8 +690,8 @@
 		 * To calculate the top of the range, we have to use the
 		 * global DEVOFFSET (dev), which can be different from offset
 		 */
-		top_of_range = (DEVOFFSET (dev) & ~(blocklen - 1)) +
-			ENVSECTORS (dev) * blocklen;
+		top_of_range = ((DEVOFFSET(dev) / blocklen) +
+				ENVSECTORS (dev)) * blocklen;
 
 		/* Limit to one block for the first read */
 		if (readlen > blocklen - block_seek)
@@ -749,9 +745,9 @@
 }
 
 /*
- * Write count bytes at offset, but stay within ENVSETCORS (dev) sectors of
- * DEVOFFSET (dev). Similar to the read case above, on NOR we erase and write
- * the whole data at once.
+ * Write count bytes at offset, but stay within ENVSECTORS (dev) sectors of
+ * DEVOFFSET (dev). Similar to the read case above, on NOR and dataflash we
+ * erase and write the whole data at once.
  */
 static int flash_write_buf (int dev, int fd, void *buf, size_t count,
 			    off_t offset, uint8_t mtd_type)
@@ -764,7 +760,7 @@
 	size_t erasesize;	/* erase / write length - one block on NAND,
 				   whole area on NOR */
 	size_t processed = 0;	/* progress counter */
-	size_t write_total;	/* total size to actually write - excludinig
+	size_t write_total;	/* total size to actually write - excluding
 				   bad blocks */
 	off_t erase_offset;	/* offset to the first erase block (aligned)
 				   below offset */
@@ -777,11 +773,10 @@
 
 	blocklen = DEVESIZE (dev);
 
-	/* Erase sector size is always a power of 2 */
-	top_of_range = (DEVOFFSET (dev) & ~(blocklen - 1)) +
-		ENVSECTORS (dev) * blocklen;
+	top_of_range = ((DEVOFFSET(dev) / blocklen) +
+					ENVSECTORS (dev)) * blocklen;
 
-	erase_offset = offset & ~(blocklen - 1);
+	erase_offset = (offset / blocklen) * blocklen;
 
 	/* Maximum area we may use */
 	erase_len = top_of_range - erase_offset;
@@ -795,7 +790,8 @@
 	 * to the start of the data, then count bytes of data, and to the
 	 * end of the block
 	 */
-	write_total = (block_seek + count + blocklen - 1) & ~(blocklen - 1);
+	write_total = ((block_seek + count + blocklen - 1) /
+						blocklen) * blocklen;
 
 	/*
 	 * Support data anywhere within erase sectors: read out the complete
@@ -838,7 +834,7 @@
 
 	erase.length = erasesize;
 
-	/* This only runs once on NOR flash */
+	/* This only runs once on NOR flash and SPI-dataflash */
 	while (processed < write_total) {
 		rc = flash_bad_block (fd, mtd_type, &blockstart);
 		if (rc < 0)		/* block test failed */
@@ -857,12 +853,14 @@
 		erase.start = blockstart;
 		ioctl (fd, MEMUNLOCK, &erase);
 
-		if (ioctl (fd, MEMERASE, &erase) != 0) {
-			fprintf (stderr, "MTD erase error on %s: %s\n",
-				 DEVNAME (dev),
-				 strerror (errno));
-			return -1;
-		}
+		/* Dataflash does not need an explicit erase cycle */
+		if (mtd_type != MTD_DATAFLASH)
+			if (ioctl (fd, MEMERASE, &erase) != 0) {
+				fprintf (stderr, "MTD erase error on %s: %s\n",
+					 DEVNAME (dev),
+					 strerror (errno));
+				return -1;
+			}
 
 		if (lseek (fd, blockstart, SEEK_SET) == -1) {
 			fprintf (stderr,
@@ -973,7 +971,9 @@
 		return -1;
 	}
 
-	if (mtdinfo.type != MTD_NORFLASH && mtdinfo.type != MTD_NANDFLASH) {
+	if (mtdinfo.type != MTD_NORFLASH &&
+	    mtdinfo.type != MTD_NANDFLASH &&
+	    mtdinfo.type != MTD_DATAFLASH) {
 		fprintf (stderr, "Unsupported flash type %u\n", mtdinfo.type);
 		return -1;
 	}
@@ -1143,6 +1143,9 @@
 		} else if (DEVTYPE(dev_current) == MTD_NANDFLASH &&
 			   DEVTYPE(!dev_current) == MTD_NANDFLASH) {
 			environment.flag_scheme = FLAG_INCREMENTAL;
+		} else if (DEVTYPE(dev_current) == MTD_DATAFLASH &&
+			   DEVTYPE(!dev_current) == MTD_DATAFLASH) {
+			environment.flag_scheme = FLAG_BOOLEAN;
 		} else {
 			fprintf (stderr, "Incompatible flash types!\n");
 			return -1;
@@ -1234,14 +1237,29 @@
 	strcpy (DEVNAME (0), DEVICE1_NAME);
 	DEVOFFSET (0) = DEVICE1_OFFSET;
 	ENVSIZE (0) = ENV1_SIZE;
+	/* Default values are: erase-size=env-size, #sectors=1 */
+	DEVESIZE (0) = ENVSIZE (0);
+	ENVSECTORS (0) = 1;
+#ifdef DEVICE1_ESIZE
 	DEVESIZE (0) = DEVICE1_ESIZE;
+#endif
+#ifdef DEVICE1_ENVSECTORS
 	ENVSECTORS (0) = DEVICE1_ENVSECTORS;
+#endif
+
 #ifdef HAVE_REDUND
 	strcpy (DEVNAME (1), DEVICE2_NAME);
 	DEVOFFSET (1) = DEVICE2_OFFSET;
 	ENVSIZE (1) = ENV2_SIZE;
+	/* Default values are: erase-size=env-size, #sectors=1 */
+	DEVESIZE (1) = ENVSIZE (1);
+	ENVSECTORS (1) = 1;
+#ifdef DEVICE2_ESIZE
 	DEVESIZE (1) = DEVICE2_ESIZE;
+#endif
+#ifdef DEVICE2_ENVSECTORS
 	ENVSECTORS (1) = DEVICE2_ENVSECTORS;
+#endif
 	HaveRedundEnv = 1;
 #endif
 #endif
@@ -1285,9 +1303,13 @@
 			     &DEVESIZE (i),
 			     &ENVSECTORS (i));
 
-		if (rc < 4)
+		if (rc < 3)
 			continue;
 
+		if (rc < 4)
+			/* Assume the erase size is the same as the env-size */
+			DEVESIZE(i) = ENVSIZE(i);
+
 		if (rc < 5)
 			/* Default - 1 sector */
 			ENVSECTORS (i) = 1;
diff --git a/tools/env/fw_env.config b/tools/env/fw_env.config
index c8f12cf..8e21d5a 100644
--- a/tools/env/fw_env.config
+++ b/tools/env/fw_env.config
@@ -1,11 +1,19 @@
 # Configuration file for fw_(printenv/saveenv) utility.
 # Up to two entries are valid, in this case the redundant
 # environment sector is assumed present.
-# Notice, that the "Number of sectors" is ignored on NOR.
+# Notice, that the "Number of sectors" is ignored on NOR and SPI-dataflash.
+# Futhermore, if the Flash sector size is ommitted, this value is assumed to
+# be the same as the Environment size, which is valid for NOR and SPI-dataflash
 
+# NOR example
 # MTD device name	Device offset	Env. size	Flash sector size	Number of sectors
 /dev/mtd1		0x0000		0x4000		0x4000
 /dev/mtd2		0x0000		0x4000		0x4000
 
+# MTD SPI-dataflash example
+# MTD device name	Device offset	Env. size	Flash sector size	Number of sectors
+#/dev/mtd5		0x4200		0x4200
+#/dev/mtd6		0x4200		0x4200
+
 # NAND example
 #/dev/mtd0		0x4000		0x4000		0x20000			2
diff --git a/tools/env/fw_env.h b/tools/env/fw_env.h
index 8130fa1..c83d608 100644
--- a/tools/env/fw_env.h
+++ b/tools/env/fw_env.h
@@ -34,10 +34,8 @@
 #define DEVICE2_NAME      "/dev/mtd2"
 #define DEVICE1_OFFSET    0x0000
 #define ENV1_SIZE         0x4000
-#define DEVICE1_ESIZE     0x4000
 #define DEVICE2_OFFSET    0x0000
 #define ENV2_SIZE         0x4000
-#define DEVICE2_ESIZE     0x4000
 
 #define CONFIG_BAUDRATE		115200
 #define CONFIG_BOOTDELAY	5	/* autoboot after 5 seconds	*/