cfi_flash: Add manufacturer-specific fixups
authorHaavard Skinnemoen <hskinnemoen@atmel.com>
Fri, 14 Dec 2007 14:36:18 +0000 (15:36 +0100)
committerStefan Roese <sr@denx.de>
Mon, 17 Dec 2007 14:48:38 +0000 (15:48 +0100)
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>
drivers/mtd/cfi_flash.c

index effcce4df861783c8a90155e80f2d0069752de96..f370e4fbd3f7d95f27eee193efc4689f0ed64322 100644 (file)
@@ -1383,20 +1383,6 @@ static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
        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;
 }
 
@@ -1567,6 +1553,49 @@ static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
        return 0;
 }
 
+/*
+ * 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 @@ ulong flash_get_size (ulong base, int banknum)
                        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);