cfi_flash: Add manufacturer-specific fixups

Run fixups based on the JEDEC manufacturer ID independent of the
command set ID.

This changes current behaviour: Previously, geometry reversal for AMD
chips were done based on the command set ID, while they are now done
based on the JEDEC manufacturer and device ID.

Also add fixup for top-boot Atmel chips. A fixup is needed for
AT49BV6416(T) too, but since u-boot currently only reads the low byte
of the device ID, there's no way to tell it apart from AT49BV642D,
which should not have this fixup. Since AT49BV642D support is
necessary to get ATNGW100 board support into mainline, I've commented
out the fixup for now.

Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index effcce4..f370e4f 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -1383,20 +1383,6 @@
 	cmdset_amd_read_jedec_ids(info);
 	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
 
-	/* check if flash geometry needs reversal */
-	if (qry->num_erase_regions > 1) {
-		/* reverse geometry if top boot part */
-		if (info->cfi_version < 0x3131) {
-			/* CFI < 1.1, try to guess from device id */
-			if ((info->device_id & 0x80) != 0)
-				cfi_reverse_geometry(qry);
-		} else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
-			/* CFI >= 1.1, deduct from top/bottom flag */
-			/* note: ext_addr is valid since cfi_version > 0 */
-			cfi_reverse_geometry(qry);
-		}
-	}
-
 	return 0;
 }
 
@@ -1568,6 +1554,49 @@
 }
 
 /*
+ * Manufacturer-specific quirks. Add workarounds for geometry
+ * reversal, etc. here.
+ */
+static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
+{
+	/* check if flash geometry needs reversal */
+	if (qry->num_erase_regions > 1) {
+		/* reverse geometry if top boot part */
+		if (info->cfi_version < 0x3131) {
+			/* CFI < 1.1, try to guess from device id */
+			if ((info->device_id & 0x80) != 0)
+				cfi_reverse_geometry(qry);
+		} else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
+			/* CFI >= 1.1, deduct from top/bottom flag */
+			/* note: ext_addr is valid since cfi_version > 0 */
+			cfi_reverse_geometry(qry);
+		}
+	}
+}
+
+static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
+{
+	int reverse_geometry = 0;
+
+	/* Check the "top boot" bit in the PRI */
+	if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
+		reverse_geometry = 1;
+
+	/* AT49BV6416(T) list the erase regions in the wrong order.
+	 * However, the device ID is identical with the non-broken
+	 * AT49BV642D since u-boot only reads the low byte (they
+	 * differ in the high byte.) So leave out this fixup for now.
+	 */
+#if 0
+	if (info->device_id == 0xd6 || info->device_id == 0xd2)
+		reverse_geometry = !reverse_geometry;
+#endif
+
+	if (reverse_geometry)
+		cfi_reverse_geometry(qry);
+}
+
+/*
  * The following code cannot be run from FLASH!
  *
  */
@@ -1629,6 +1658,16 @@
 			return 0;
 		}
 
+		/* Do manufacturer-specific fixups */
+		switch (info->manufacturer_id) {
+		case 0x0001:
+			flash_fixup_amd(info, &qry);
+			break;
+		case 0x001f:
+			flash_fixup_atmel(info, &qry);
+			break;
+		}
+
 		debug ("manufacturer is %d\n", info->vendor);
 		debug ("manufacturer id is 0x%x\n", info->manufacturer_id);
 		debug ("device id is 0x%x\n", info->device_id);