Update all server port command to use new helper.
[fw/openocd] / src / flash / cfi.c
index 8ead20825689c592c37e11556cb9226f56b90064..2d75ff4480577f89fb5b6a8d586d5c172293581b 100644 (file)
@@ -74,7 +74,7 @@ static void cfi_fixup_0002_unlock_addresses(flash_bank_t *flash, void *param);
 static void cfi_fixup_atmel_reversed_erase_regions(flash_bank_t *flash, void *param);
 
 /* fixup after reading cmdset 0002 primary query table */
-static cfi_fixup_t cfi_0002_fixups[] = {
+static const cfi_fixup_t cfi_0002_fixups[] = {
        {CFI_MFR_SST, 0x00D4, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
        {CFI_MFR_SST, 0x00D5, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
        {CFI_MFR_SST, 0x00D6, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
@@ -90,14 +90,14 @@ static cfi_fixup_t cfi_0002_fixups[] = {
 };
 
 /* fixup after reading cmdset 0001 primary query table */
-static cfi_fixup_t cfi_0001_fixups[] = {
+static const cfi_fixup_t cfi_0001_fixups[] = {
        {0, 0, NULL, NULL}
 };
 
-static void cfi_fixup(flash_bank_t *bank, cfi_fixup_t *fixups)
+static void cfi_fixup(flash_bank_t *bank, const cfi_fixup_t *fixups)
 {
        cfi_flash_bank_t *cfi_info = bank->driver_priv;
-       cfi_fixup_t *f;
+       const cfi_fixup_t *f;
 
        for (f = fixups; f->fixup; f++)
        {
@@ -1125,11 +1125,11 @@ static int cfi_intel_write_block(struct flash_bank_s *bank, uint8_t *buffer, uin
        armv4_5_info.core_state = ARMV4_5_STATE_ARM;
 
        /* If we are setting up the write_algorith, we need target_code_src */
-       /* if not we only need target_code_size.                                                                                                                */
-       /*                                                                                                                                                                                                                                                                      */
-       /* However, we don't want to create multiple code paths, so we                  */
-       /* do the unecessary evaluation of target_code_src, which the                   */
-       /* compiler will probably nicely optimize away if not needed                            */
+       /* if not we only need target_code_size. */
+
+       /* However, we don't want to create multiple code paths, so we */
+       /* do the unecessary evaluation of target_code_src, which the */
+       /* compiler will probably nicely optimize away if not needed */
 
        /* prepare algorithm code for target endian */
        switch (bank->bus_width)
@@ -1384,6 +1384,31 @@ static int cfi_spansion_write_block(struct flash_bank_s *bank, uint8_t *buffer,
                0xeafffffe      /* b    81ac <sp_16_done>              */
                };
 
+               static const uint32_t word_16_code_dq7only[] = {
+                               /* <sp_16_code>:                       */
+               0xe0d050b2,     /* ldrh r5, [r0], #2                   */
+               0xe1c890b0,     /* strh r9, [r8]                       */
+               0xe1cab0b0,     /* strh r11, [r10]                              */
+               0xe1c830b0,     /* strh r3, [r8]                                */
+               0xe1c150b0,     /* strh r5, [r1]                       */
+               0xe1a00000,     /* nop                  (mov r0,r0)    */
+                               /*                                     */
+                               /* <sp_16_busy>:                       */
+               0xe1d160b0,     /* ldrh r6, [r1]                       */
+               0xe0257006,     /* eor  r7, r5, r6                     */
+               0xe2177080,     /* ands r7, #0x80                      */
+               0x1afffffb,     /* bne  8168 <sp_16_busy>              */
+                               /*                                     */
+               0xe2522001,     /* subs r2, r2, #1      ; 0x1          */
+               0x03a05080,     /* moveq        r5, #128        ; 0x80 */
+               0x0a000001,     /* beq  81ac <sp_16_done>              */
+               0xe2811002,     /* add  r1, r1, #2      ; 0x2          */
+               0xeafffff0,     /* b    8158 <sp_16_code>              */
+                               /*                                     */
+                               /* 000081ac <sp_16_done>:              */
+               0xeafffffe      /* b    81ac <sp_16_done>              */
+               };
+
                static const uint32_t word_8_code[] = {
                                /* 000081b0 <sp_16_code_end>:          */
                0xe4d05001,     /* ldrb r5, [r0], #1                   */
@@ -1422,34 +1447,46 @@ static int cfi_spansion_write_block(struct flash_bank_s *bank, uint8_t *buffer,
        armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
        armv4_5_info.core_state = ARMV4_5_STATE_ARM;
 
+       int target_code_size;
+       const uint32_t *target_code_src;
+
+       switch (bank->bus_width)
+       {
+       case 1 :
+               target_code_src = word_8_code;
+               target_code_size = sizeof(word_8_code);
+               break;
+       case 2 :
+               /* Check for DQ5 support */
+               if( cfi_info->status_poll_mask & (1 << 5) )
+               {
+                       target_code_src = word_16_code;
+                       target_code_size = sizeof(word_16_code);
+               }
+               else
+               {
+                       /* No DQ5 support. Use DQ7 DATA# polling only. */
+                       target_code_src = word_16_code_dq7only;
+                       target_code_size = sizeof(word_16_code_dq7only);
+               }
+               break;
+       case 4 :
+               target_code_src = word_32_code;
+               target_code_size = sizeof(word_32_code);
+               break;
+       default:
+               LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
        /* flash write code */
        if (!cfi_info->write_algorithm)
        {
                uint8_t *target_code;
-               int target_code_size;
-               const uint32_t *src;
 
                /* convert bus-width dependent algorithm code to correct endiannes */
-               switch (bank->bus_width)
-               {
-               case 1:
-                       src = word_8_code;
-                       target_code_size = sizeof(word_8_code);
-                       break;
-               case 2:
-                       src = word_16_code;
-                       target_code_size = sizeof(word_16_code);
-                       break;
-               case 4:
-                       src = word_32_code;
-                       target_code_size = sizeof(word_32_code);
-                       break;
-               default:
-                       LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width);
-                       return ERROR_FLASH_OPERATION_FAILED;
-               }
                target_code = malloc(target_code_size);
-               cfi_fix_code_endian(target, target_code, src, target_code_size / 4);
+               cfi_fix_code_endian(target, target_code, target_code_src, target_code_size / 4);
 
                /* allocate working area */
                retval = target_alloc_working_area(target, target_code_size,
@@ -1515,7 +1552,7 @@ static int cfi_spansion_write_block(struct flash_bank_s *bank, uint8_t *buffer,
 
                retval = target_run_algorithm(target, 0, NULL, 10, reg_params,
                                                     cfi_info->write_algorithm->address,
-                                                    cfi_info->write_algorithm->address + ((24 * 4) - 4),
+                                                    cfi_info->write_algorithm->address + ((target_code_size) - 4),
                                                     10000, &armv4_5_info);
 
                status = buf_get_u32(reg_params[5].value, 0, 32);
@@ -1532,7 +1569,7 @@ static int cfi_spansion_write_block(struct flash_bank_s *bank, uint8_t *buffer,
                count -= thisrun_count;
        }
 
-       target_free_working_area(target, source);
+       target_free_all_working_areas(target);
 
        destroy_reg_param(&reg_params[0]);
        destroy_reg_param(&reg_params[1]);
@@ -2106,6 +2143,45 @@ static void cfi_fixup_0002_unlock_addresses(flash_bank_t *bank, void *param)
        pri_ext->_unlock2 = unlock_addresses->unlock2;
 }
 
+
+static int cfi_query_string(struct flash_bank_s *bank, int address)
+{
+       cfi_flash_bank_t *cfi_info = bank->driver_priv;
+       target_t *target = bank->target;
+       int retval;
+       uint8_t command[8];
+
+       cfi_command(bank, 0x98, command);
+       if ((retval = target_write_memory(target, flash_address(bank, 0, address), bank->bus_width, 1, command)) != ERROR_OK)
+       {
+               return retval;
+       }
+
+       cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10);
+       cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11);
+       cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12);
+
+       LOG_DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]);
+
+       if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y'))
+       {
+               cfi_command(bank, 0xf0, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               cfi_command(bank, 0xff, command);
+               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
+               {
+                       return retval;
+               }
+               LOG_ERROR("Could not probe bank: no QRY");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       return ERROR_OK;
+}
+
 static int cfi_probe(struct flash_bank_s *bank)
 {
        cfi_flash_bank_t *cfi_info = bank->driver_priv;
@@ -2172,7 +2248,7 @@ static int cfi_probe(struct flash_bank_s *bank)
                {
                        return retval;
                }
-               if ((retval = target_read_u16(target, flash_address(bank, 0, 0x02), &cfi_info->device_id)) != ERROR_OK)
+               if ((retval = target_read_u16(target, flash_address(bank, 0, 0x01), &cfi_info->device_id)) != ERROR_OK)
                {
                        return retval;
                }
@@ -2199,6 +2275,8 @@ static int cfi_probe(struct flash_bank_s *bank)
         */
        if (cfi_info->not_cfi == 0)
        {
+               int retval;
+
                /* enter CFI query mode
                 * according to JEDEC Standard No. 68.01,
                 * a single bus sequence with address = 0x55, data = 0x98 should put
@@ -2206,33 +2284,21 @@ static int cfi_probe(struct flash_bank_s *bank)
                 *
                 * SST flashes clearly violate this, and we will consider them incompatbile for now
                 */
-               cfi_command(bank, 0x98, command);
-               if ((retval = target_write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command)) != ERROR_OK)
-               {
-                       return retval;
-               }
 
-               cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10);
-               cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11);
-               cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12);
-
-               LOG_DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]);
-
-               if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y'))
+               retval = cfi_query_string(bank, 0x55);
+               if (retval != ERROR_OK)
                {
-                       cfi_command(bank, 0xf0, command);
-                       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       cfi_command(bank, 0xff, command);
-                       if ((retval = target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command)) != ERROR_OK)
-                       {
-                               return retval;
-                       }
-                       LOG_ERROR("Could not probe bank: no QRY");
-                       return ERROR_FLASH_BANK_INVALID;
+                       /*
+                        * Spansion S29WS-N CFI query fix is to try 0x555 if 0x55 fails. Should
+                        * be harmless enough:
+                        *
+                        * http://www.infradead.org/pipermail/linux-mtd/2005-September/013618.html
+                        */
+                       LOG_USER("Try workaround w/0x555 instead of 0x55 to get QRY.");
+                       retval = cfi_query_string(bank, 0x555);
                }
+               if (retval != ERROR_OK)
+                       return retval;
 
                cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13);
                cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15);
@@ -2383,9 +2449,10 @@ static int cfi_probe(struct flash_bank_s *bank)
                                sector++;
                        }
                }
-               if (offset != cfi_info->dev_size)
+               if (offset != (cfi_info->dev_size * bank->bus_width / bank->chip_width))
                {
-                       LOG_WARNING("CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", cfi_info->dev_size, offset);
+                       LOG_WARNING("CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", \
+                               (cfi_info->dev_size * bank->bus_width / bank->chip_width), offset);
                }
        }