cfi_protect is not implemented on Spansion flashes (many do not even have protection...
[fw/openocd] / src / flash / nor / cfi.c
index 9a1e8d73aa8ec7146fafa1332153da9b6c9ea56e..f25f46d93d43447663e7f6c50de1764329a8c765 100644 (file)
@@ -46,9 +46,10 @@ static struct cfi_unlock_addresses cfi_unlock_addresses[] =
 };
 
 /* CFI fixups foward declarations */
-static void cfi_fixup_0002_erase_regions(struct flash_bank *flash, void *param);
-static void cfi_fixup_0002_unlock_addresses(struct flash_bank *flash, void *param);
-static void cfi_fixup_reversed_erase_regions(struct flash_bank *flash, void *param);
+static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, void *param);
+static void cfi_fixup_0002_unlock_addresses(struct flash_bank *bank, void *param);
+static void cfi_fixup_reversed_erase_regions(struct flash_bank *bank, void *param);
+static void cfi_fixup_0002_write_buffer(struct flash_bank *bank, void *param);
 
 /* fixup after reading cmdset 0002 primary query table */
 static const struct cfi_fixup cfi_0002_fixups[] = {
@@ -59,13 +60,14 @@ static const struct cfi_fixup cfi_0002_fixups[] = {
        {CFI_MFR_SST, 0x2780, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
        {CFI_MFR_SST, 0x236d, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
        {CFI_MFR_ATMEL, 0x00C8, cfi_fixup_reversed_erase_regions, NULL},
-       {CFI_MFR_ST,  0x22C4, cfi_fixup_reversed_erase_regions, NULL}, /* M29W160ET */
+       {CFI_MFR_ST, 0x22C4, cfi_fixup_reversed_erase_regions, NULL}, /* M29W160ET */
        {CFI_MFR_FUJITSU, 0x22ea, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
        {CFI_MFR_FUJITSU, 0x226b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
        {CFI_MFR_AMIC, 0xb31a, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
        {CFI_MFR_MX, 0x225b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
        {CFI_MFR_AMD, 0x225b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]},
        {CFI_MFR_ANY, CFI_ID_ANY, cfi_fixup_0002_erase_regions, NULL},
+       {CFI_MFR_ST, 0x227E, cfi_fixup_0002_write_buffer, NULL}, /* M29W128G */
        {0, 0, NULL, NULL}
 };
 
@@ -880,8 +882,7 @@ static int cfi_intel_erase(struct flash_bank *bank, int first, int last)
                }
 
                uint8_t status;
-               retval = cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->block_erase_timeout_typ),
-                               &status);
+               retval = cfi_intel_wait_status_busy(bank, cfi_info->block_erase_timeout, &status);
                if (retval != ERROR_OK)
                        return retval;
 
@@ -947,8 +948,7 @@ static int cfi_spansion_erase(struct flash_bank *bank, int first, int last)
                        return retval;
                }
 
-               if (cfi_spansion_wait_status_busy(bank,
-                               1000 * (1 << cfi_info->block_erase_timeout_typ)) == ERROR_OK)
+               if (cfi_spansion_wait_status_busy(bank, cfi_info->block_erase_timeout) == ERROR_OK)
                {
                        bank->sectors[i].is_erased = 1;
                }
@@ -1163,8 +1163,8 @@ static int cfi_protect(struct flash_bank *bank, int set, int first, int last)
                        return cfi_intel_protect(bank, set, first, last);
                        break;
                default:
-                       LOG_ERROR("protect: cfi primary command set %i unsupported", cfi_info->pri_id);
-                       return ERROR_FAIL;
+                       LOG_WARNING("protect: cfi primary command set %i unsupported", cfi_info->pri_id);
+                       return ERROR_OK;
        }
 }
 
@@ -1226,6 +1226,7 @@ static int cfi_intel_write_block(struct flash_bank *bank, uint8_t *buffer,
         * r6: error test pattern
         */
 
+       /* see contib/loaders/flash/armv4_5_cfi_intel_32.s for src */
        static const uint32_t word_32_code[] = {
                0xe4904004,   /* loop:  ldr r4, [r0], #4 */
                0xe5813000,   /*                str r3, [r1] */
@@ -1243,6 +1244,7 @@ static int cfi_intel_write_block(struct flash_bank *bank, uint8_t *buffer,
                0xeafffffe    /* done:  b -2 */
        };
 
+       /* see contib/loaders/flash/armv4_5_cfi_intel_16.s for src */
        static const uint32_t word_16_code[] = {
                0xe0d040b2,   /* loop:  ldrh r4, [r0], #2 */
                0xe1c130b0,   /*                strh r3, [r1] */
@@ -1260,6 +1262,7 @@ static int cfi_intel_write_block(struct flash_bank *bank, uint8_t *buffer,
                0xeafffffe    /* done:  b -2 */
        };
 
+       /* see contib/loaders/flash/armv4_5_cfi_intel_8.s for src */
        static const uint32_t word_8_code[] = {
                0xe4d04001,   /* loop:  ldrb r4, [r0], #1 */
                0xe5c13000,   /*                strb r3, [r1] */
@@ -1487,6 +1490,7 @@ static int cfi_spansion_write_block(struct flash_bank *bank, uint8_t *buffer,
        /*  R10 = unlock2_addr */
        /*  R11 = unlock2_cmd */
 
+       /* see contib/loaders/flash/armv4_5_cfi_span_32.s for src */
        static const uint32_t word_32_code[] = {
                                                /* 00008100 <sp_32_code>:               */
                0xe4905004,             /* ldr  r5, [r0], #4                    */
@@ -1519,9 +1523,10 @@ static int cfi_spansion_write_block(struct flash_bank *bank, uint8_t *buffer,
                                                /*                                                              */
                                                /* 00008154 <sp_32_done>:               */
                0xeafffffe              /* b    8154 <sp_32_done>               */
-               };
+       };
 
-               static const uint32_t word_16_code[] = {
+       /* see contib/loaders/flash/armv4_5_cfi_span_16.s for src */
+       static const uint32_t word_16_code[] = {
                                                /* 00008158 <sp_16_code>:               */
                0xe0d050b2,             /* ldrh r5, [r0], #2                    */
                0xe1c890b0,             /* strh r9, [r8]                                */
@@ -1553,9 +1558,10 @@ static int cfi_spansion_write_block(struct flash_bank *bank, uint8_t *buffer,
                                                /*                                                              */
                                                /* 000081ac <sp_16_done>:               */
                0xeafffffe              /* b    81ac <sp_16_done>               */
-               };
+       };
 
-               static const uint32_t word_16_code_dq7only[] = {
+       /* see contib/loaders/flash/armv4_5_cfi_span_16_dq7.s for src */
+       static const uint32_t word_16_code_dq7only[] = {
                                                /* <sp_16_code>:                                */
                0xe0d050b2,             /* ldrh r5, [r0], #2                    */
                0xe1c890b0,             /* strh r9, [r8]                                */
@@ -1578,9 +1584,10 @@ static int cfi_spansion_write_block(struct flash_bank *bank, uint8_t *buffer,
                                                /*                                                              */
                                                /* 000081ac <sp_16_done>:               */
                0xeafffffe              /* b    81ac <sp_16_done>               */
-               };
+       };
 
-               static const uint32_t word_8_code[] = {
+       /* see contib/loaders/flash/armv4_5_cfi_span_8.s for src */
+       static const uint32_t word_8_code[] = {
                                                /* 000081b0 <sp_16_code_end>:   */
                0xe4d05001,             /* ldrb r5, [r0], #1                    */
                0xe5c89000,             /* strb r9, [r8]                                */
@@ -1787,8 +1794,7 @@ static int cfi_intel_write_word(struct flash_bank *bank, uint8_t *word, uint32_t
        }
 
        uint8_t status;
-       retval = cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max),
-                       &status);
+       retval = cfi_intel_wait_status_busy(bank, cfi_info->word_write_timeout, &status);
        if (retval != 0x80)
        {
                if ((retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0))) != ERROR_OK)
@@ -1796,7 +1802,7 @@ static int cfi_intel_write_word(struct flash_bank *bank, uint8_t *word, uint32_t
                        return retval;
                }
 
-               LOG_ERROR("couldn't write word at base 0x%" PRIx32 ", address %" PRIx32,
+               LOG_ERROR("couldn't write word at base 0x%" PRIx32 ", address 0x%" PRIx32,
                                bank->base, address);
                return ERROR_FLASH_OPERATION_FAILED;
        }
@@ -1821,7 +1827,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, uint8_t *word,
        /* Check for valid range */
        if (address & buffermask)
        {
-               LOG_ERROR("Write address at base 0x%" PRIx32 ", address %" PRIx32
+               LOG_ERROR("Write address at base 0x%" PRIx32 ", address 0x%" PRIx32
                                " not aligned to 2^%d boundary",
                                bank->base, address, cfi_info->max_buf_write_size);
                return ERROR_FLASH_OPERATION_FAILED;
@@ -1844,8 +1850,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, uint8_t *word,
                return retval;
        }
        uint8_t status;
-       retval = cfi_intel_wait_status_busy(bank,
-                       1000 * (1 << cfi_info->buf_write_timeout_max), &status);
+       retval = cfi_intel_wait_status_busy(bank, cfi_info->buf_write_timeout, &status);
        if (retval != ERROR_OK)
                return retval;
        if (status != 0x80)
@@ -1855,7 +1860,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, uint8_t *word,
                        return retval;
                }
 
-               LOG_ERROR("couldn't start buffer write operation at base 0x%" PRIx32 ", address %" PRIx32,
+               LOG_ERROR("couldn't start buffer write operation at base 0x%" PRIx32 ", address 0x%" PRIx32,
                                bank->base, address);
                return ERROR_FLASH_OPERATION_FAILED;
        }
@@ -1878,8 +1883,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, uint8_t *word,
                return retval;
        }
 
-       retval = cfi_intel_wait_status_busy(bank,
-                       1000 * (1 << cfi_info->buf_write_timeout_max), &status);
+       retval = cfi_intel_wait_status_busy(bank, cfi_info->buf_write_timeout, &status);
        if (retval != ERROR_OK)
                return retval;
 
@@ -1892,7 +1896,7 @@ static int cfi_intel_write_words(struct flash_bank *bank, uint8_t *word,
                }
 
                LOG_ERROR("Buffer write at base 0x%" PRIx32
-                               ", address %" PRIx32 " failed.", bank->base, address);
+                               ", address 0x%" PRIx32 " failed.", bank->base, address);
                return ERROR_FLASH_OPERATION_FAILED;
        }
 
@@ -1930,8 +1934,7 @@ static int cfi_spansion_write_word(struct flash_bank *bank, uint8_t *word, uint3
                return retval;
        }
 
-       if (cfi_spansion_wait_status_busy(bank,
-                       1000 * (1 << cfi_info->word_write_timeout_max)) != ERROR_OK)
+       if (cfi_spansion_wait_status_busy(bank, cfi_info->word_write_timeout) != ERROR_OK)
        {
                if ((retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0))) != ERROR_OK)
                {
@@ -1939,7 +1942,7 @@ static int cfi_spansion_write_word(struct flash_bank *bank, uint8_t *word, uint3
                }
 
                LOG_ERROR("couldn't write word at base 0x%" PRIx32
-                               ", address %" PRIx32 , bank->base, address);
+                               ", address 0x%" PRIx32 , bank->base, address);
                return ERROR_FLASH_OPERATION_FAILED;
        }
 
@@ -1965,7 +1968,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, uint8_t *word,
        if (address & buffermask)
        {
                LOG_ERROR("Write address at base 0x%" PRIx32
-                               ", address %" PRIx32 " not aligned to 2^%d boundary",
+                               ", address 0x%" PRIx32 " not aligned to 2^%d boundary",
                                bank->base, address, cfi_info->max_buf_write_size);
                return ERROR_FLASH_OPERATION_FAILED;
        }
@@ -1978,7 +1981,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, uint8_t *word,
                return ERROR_FLASH_OPERATION_FAILED;
        }
 
-       // Unlock
+       /* Unlock */
        if ((retval = cfi_send_command(bank, 0xaa,
                        flash_address(bank, 0, pri_ext->_unlock1))) != ERROR_OK)
        {
@@ -1991,15 +1994,14 @@ static int cfi_spansion_write_words(struct flash_bank *bank, uint8_t *word,
                return retval;
        }
 
-       // Buffer load command
+       /* Buffer load command */
        if ((retval = cfi_send_command(bank, 0x25, address)) != ERROR_OK)
        {
                return retval;
        }
 
        /* Write buffer wordcount-1 and data words */
-       if ((retval = cfi_send_command(bank,
-                       bufferwsize-1, address)) != ERROR_OK)
+       if ((retval = cfi_send_command(bank, bufferwsize-1, address)) != ERROR_OK)
        {
                return retval;
        }
@@ -2016,8 +2018,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, uint8_t *word,
                return retval;
        }
 
-       if (cfi_spansion_wait_status_busy(bank,
-                       1000 * (1 << cfi_info->word_write_timeout_max)) != ERROR_OK)
+       if (cfi_spansion_wait_status_busy(bank, cfi_info->buf_write_timeout) != ERROR_OK)
        {
                if ((retval = cfi_send_command(bank, 0xf0,
                                flash_address(bank, 0, 0x0))) != ERROR_OK)
@@ -2026,7 +2027,7 @@ static int cfi_spansion_write_words(struct flash_bank *bank, uint8_t *word,
                }
 
                LOG_ERROR("couldn't write block at base 0x%" PRIx32
-                               ", address %" PRIx32 ", size %" PRIx32, bank->base, address, bufferwsize);
+                               ", address 0x%" PRIx32 ", size 0x%" PRIx32, bank->base, address, bufferwsize);
                return ERROR_FLASH_OPERATION_FAILED;
        }
 
@@ -2059,6 +2060,13 @@ static int cfi_write_words(struct flash_bank *bank, uint8_t *word,
 {
        struct cfi_flash_bank *cfi_info = bank->driver_priv;
 
+       if (cfi_info->buf_write_timeout_typ == 0)
+       {
+               /* buffer writes are not supported */
+               LOG_DEBUG("Buffer Writes Not Supported");
+               return ERROR_FLASH_OPER_UNSUPPORTED;
+       }
+
        switch (cfi_info->pri_id)
        {
                case 1:
@@ -2235,7 +2243,7 @@ static int cfi_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset,
                                int fallback;
                                if ((write_p & 0xff) == 0)
                                {
-                                       LOG_INFO("Programming at %08" PRIx32 ", count %08"
+                                       LOG_INFO("Programming at 0x%08" PRIx32 ", count 0x%08"
                                                        PRIx32 " bytes remaining", write_p, count);
                                }
                                fallback = 1;
@@ -2249,6 +2257,8 @@ static int cfi_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset,
                                                count -= buffersize;
                                                fallback = 0;
                                        }
+                                       else if (retval != ERROR_FLASH_OPER_UNSUPPORTED)
+                                               return retval;
                                }
                                /* try the slow way? */
                                if (fallback)
@@ -2527,6 +2537,7 @@ static int cfi_probe(struct flash_bank *bank)
                retval = cfi_query_u8(bank, 0, 0x1e, &cfi_info->vpp_max);
                if (retval != ERROR_OK)
                        return retval;
+
                retval = cfi_query_u8(bank, 0, 0x1f, &cfi_info->word_write_timeout_typ);
                if (retval != ERROR_OK)
                        return retval;
@@ -2552,24 +2563,6 @@ static int cfi_probe(struct flash_bank *bank)
                if (retval != ERROR_OK)
                        return retval;
 
-               LOG_DEBUG("Vcc min: %x.%x, Vcc max: %x.%x, Vpp min: %u.%x, Vpp max: %u.%x",
-                       (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
-                       (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
-                       (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
-                       (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
-
-               LOG_DEBUG("typ. word write timeout: %u us, typ. buf write timeout: %u us, "
-                               "typ. block erase timeout: %u ms, typ. chip erase timeout: %u ms",
-                               1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ,
-                               1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ);
-
-               LOG_DEBUG("max. word write timeout: %u us, max. buf write timeout: %u us, "
-                               "max. block erase timeout: %u ms, max. chip erase timeout: %u ms",
-                               (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
-                               (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
-                               (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
-                               (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
-
                uint8_t data;
                retval = cfi_query_u8(bank, 0, 0x27, &data);
                if (retval != ERROR_OK)
@@ -2586,7 +2579,7 @@ static int cfi_probe(struct flash_bank *bank)
                if (retval != ERROR_OK)
                        return retval;
 
-               LOG_DEBUG("size: 0x%" PRIx32 ", interface desc: %i, max buffer write size: %x",
+               LOG_DEBUG("size: 0x%" PRIx32 ", interface desc: %i, max buffer write size: 0x%x",
                                cfi_info->dev_size, cfi_info->interface_desc, (1 << cfi_info->max_buf_write_size));
 
                if (cfi_info->num_erase_regions)
@@ -2637,6 +2630,39 @@ static int cfi_probe(struct flash_bank *bank)
                }
        } /* end CFI case */
 
+       LOG_DEBUG("Vcc min: %x.%x, Vcc max: %x.%x, Vpp min: %u.%x, Vpp max: %u.%x",
+               (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
+               (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
+               (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
+               (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
+
+       LOG_DEBUG("typ. word write timeout: %u us, typ. buf write timeout: %u us, "
+                       "typ. block erase timeout: %u ms, typ. chip erase timeout: %u ms",
+                       1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ,
+                       1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ);
+
+       LOG_DEBUG("max. word write timeout: %u us, max. buf write timeout: %u us, "
+                       "max. block erase timeout: %u ms, max. chip erase timeout: %u ms",
+                       (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
+                       (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
+                       (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
+                       (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
+
+       /* convert timeouts to real values in ms */
+       cfi_info->word_write_timeout = DIV_ROUND_UP((1L << cfi_info->word_write_timeout_typ) *
+                               (1L << cfi_info->word_write_timeout_max), 1000);
+       cfi_info->buf_write_timeout = DIV_ROUND_UP((1L << cfi_info->buf_write_timeout_typ) *
+                               (1L << cfi_info->buf_write_timeout_max), 1000);
+       cfi_info->block_erase_timeout = (1L << cfi_info->block_erase_timeout_typ) *
+                               (1L << cfi_info->block_erase_timeout_max);
+       cfi_info->chip_erase_timeout = (1L << cfi_info->chip_erase_timeout_typ) *
+                               (1L << cfi_info->chip_erase_timeout_max);
+
+       LOG_DEBUG("calculated word write timeout: %u ms, buf write timeout: %u ms, "
+                       "block erase timeout: %u ms, chip erase timeout: %u ms",
+                       cfi_info->word_write_timeout, cfi_info->buf_write_timeout,
+                       cfi_info->block_erase_timeout, cfi_info->chip_erase_timeout);
+
        /* apply fixups depending on the primary command set */
        switch (cfi_info->pri_id)
        {
@@ -2832,82 +2858,87 @@ static int get_cfi_info(struct flash_bank *bank, char *buf, int buf_size)
        }
 
        if (cfi_info->not_cfi == 0)
-               printed = snprintf(buf, buf_size, "\ncfi information:\n");
+               printed = snprintf(buf, buf_size, "\nCFI flash: ");
        else
-               printed = snprintf(buf, buf_size, "\nnon-cfi flash:\n");
+               printed = snprintf(buf, buf_size, "\nnon-CFI flash: ");
        buf += printed;
        buf_size -= printed;
 
-       printed = snprintf(buf, buf_size, "\nmfr: 0x%4.4x, id:0x%4.4x\n",
+       printed = snprintf(buf, buf_size, "mfr: 0x%4.4x, id:0x%4.4x\n\n",
                cfi_info->manufacturer, cfi_info->device_id);
        buf += printed;
        buf_size -= printed;
 
-       if (cfi_info->not_cfi == 0)
-       {
-               printed = snprintf(buf, buf_size, "qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: "
-                               "0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x\n",
-                               cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2],
-                               cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
-               buf += printed;
-               buf_size -= printed;
-
-               printed = snprintf(buf, buf_size, "Vcc min: %x.%x, Vcc max: %x.%x, "
-                               "Vpp min: %u.%x, Vpp max: %u.%x\n",
-                               (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
-                               (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
-                               (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
-                               (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
-               buf += printed;
-               buf_size -= printed;
-
-               printed = snprintf(buf, buf_size, "typ. word write timeout: %u us, "
-                               "typ. buf write timeout: %u us, "
-                               "typ. block erase timeout: %u ms, "
-                               "typ. chip erase timeout: %u ms\n",
-                               1 << cfi_info->word_write_timeout_typ,
-                               1 << cfi_info->buf_write_timeout_typ,
-                               1 << cfi_info->block_erase_timeout_typ,
-                               1 << cfi_info->chip_erase_timeout_typ);
-               buf += printed;
-               buf_size -= printed;
-
-               printed = snprintf(buf, buf_size, "max. word write timeout: %u us, "
-                               "max. buf write timeout: %u us, max. "
-                               "block erase timeout: %u ms, max. chip erase timeout: %u ms\n",
-                               (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
-                               (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
-                               (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
-                               (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
-               buf += printed;
-               buf_size -= printed;
-
-               printed = snprintf(buf, buf_size, "size: 0x%" PRIx32 ", interface desc: %i, "
-                               "max buffer write size: %x\n",
-                               cfi_info->dev_size,
-                               cfi_info->interface_desc,
-                               1 << cfi_info->max_buf_write_size);
-               buf += printed;
-               buf_size -= printed;
+       printed = snprintf(buf, buf_size, "qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: "
+                       "0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x\n",
+                       cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2],
+                       cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
+       buf += printed;
+       buf_size -= printed;
 
-               switch (cfi_info->pri_id)
-               {
-                       case 1:
-                       case 3:
-                               cfi_intel_info(bank, buf, buf_size);
-                               break;
-                       case 2:
-                               cfi_spansion_info(bank, buf, buf_size);
-                               break;
-                       default:
-                               LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
-                               break;
-               }
+       printed = snprintf(buf, buf_size, "Vcc min: %x.%x, Vcc max: %x.%x, "
+                       "Vpp min: %u.%x, Vpp max: %u.%x\n",
+                       (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
+                       (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
+                       (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
+                       (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf, buf_size, "typ. word write timeout: %u us, "
+                       "typ. buf write timeout: %u us, "
+                       "typ. block erase timeout: %u ms, "
+                       "typ. chip erase timeout: %u ms\n",
+                       1 << cfi_info->word_write_timeout_typ,
+                       1 << cfi_info->buf_write_timeout_typ,
+                       1 << cfi_info->block_erase_timeout_typ,
+                       1 << cfi_info->chip_erase_timeout_typ);
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf, buf_size, "max. word write timeout: %u us, "
+                       "max. buf write timeout: %u us, max. "
+                       "block erase timeout: %u ms, max. chip erase timeout: %u ms\n",
+                       (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
+                       (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
+                       (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
+                       (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
+       buf += printed;
+       buf_size -= printed;
+
+       printed = snprintf(buf, buf_size, "size: 0x%" PRIx32 ", interface desc: %i, "
+                       "max buffer write size: 0x%x\n",
+                       cfi_info->dev_size,
+                       cfi_info->interface_desc,
+                       1 << cfi_info->max_buf_write_size);
+       buf += printed;
+       buf_size -= printed;
+
+       switch (cfi_info->pri_id)
+       {
+               case 1:
+               case 3:
+                       cfi_intel_info(bank, buf, buf_size);
+                       break;
+               case 2:
+                       cfi_spansion_info(bank, buf, buf_size);
+                       break;
+               default:
+                       LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+                       break;
        }
 
        return ERROR_OK;
 }
 
+static void cfi_fixup_0002_write_buffer(struct flash_bank *bank, void *param)
+{
+       struct cfi_flash_bank *cfi_info = bank->driver_priv;
+
+       /* disable write buffer for M29W128G */
+       cfi_info->buf_write_timeout_typ = 0;
+}
+
 struct flash_driver cfi_flash = {
        .name = "cfi",
        .flash_bank_command = cfi_flash_bank_command,