Nicolas Pitre nico at cam.org software ECC computation for NAND flash
[fw/openocd] / src / flash / str9x.c
index 150f0f87353ce985da600ffb26196c88c77fcbbe..1160c7090a91ca36f2240cfdd0e97c21fca653d6 100644 (file)
@@ -2,6 +2,12 @@
  *   Copyright (C) 2005 by Dominic Rath                                    *
  *   Dominic.Rath@gmx.de                                                   *
  *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *
+ *   Copyright (C) 2008 by Oyvind Harboe                                   *
+ *   oyvind.harboe@zylin.com                                               *
+ *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
  *   the Free Software Foundation; either version 2 of the License, or     *
@@ -180,6 +186,7 @@ int str9x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char
 
 int str9x_protect_check(struct flash_bank_s *bank)
 {
+       int retval;
        str9x_flash_bank_t *str9x_info = bank->driver_priv;
        target_t *target = bank->target;
        
@@ -189,6 +196,7 @@ int str9x_protect_check(struct flash_bank_s *bank)
 
        if (bank->target->state != TARGET_HALTED)
        {
+               LOG_ERROR("Target not halted");
                return ERROR_TARGET_NOT_HALTED;
        }
 
@@ -199,25 +207,46 @@ int str9x_protect_check(struct flash_bank_s *bank)
                if (str9x_info->bank1)
                {
                        adr = bank1start + 0x18;
-                       target_write_u16(target, adr, 0x90);
-                       target_read_u16(target, adr, (u16*)&status);
+                       if ((retval=target_write_u16(target, adr, 0x90))!=ERROR_OK)
+                       {
+                               return retval;
+                       }
+                       if ((retval=target_read_u16(target, adr, (u16*)&status))!=ERROR_OK)
+                       {
+                               return retval;
+                       }
                }
                else
                {
                        adr = bank1start + 0x14;
-                       target_write_u16(target, adr, 0x90);
-                       target_read_u32(target, adr, &status);
+                       if ((retval=target_write_u16(target, adr, 0x90))!=ERROR_OK)
+                       {
+                               return retval;
+                       }
+                       if ((retval=target_read_u32(target, adr, &status))!=ERROR_OK)
+                       {
+                               return retval;
+                       }
                }
        }
        else
        {
                adr = bank1start + 0x10;
-               target_write_u16(target, adr, 0x90);
-               target_read_u16(target, adr, (u16*)&status);
+               if ((retval=target_write_u16(target, adr, 0x90))!=ERROR_OK)
+               {
+                       return retval;
+               }
+               if ((retval=target_read_u16(target, adr, (u16*)&status))!=ERROR_OK)
+               {
+                       return retval;
+               }
        }
        
        /* read array command */
-       target_write_u16(target, adr, 0xFF);
+       if ((retval=target_write_u16(target, adr, 0xFF))!=ERROR_OK)
+       {
+               return retval;
+       }
        
        for (i = 0; i < bank->num_sectors; i++)
        {
@@ -236,41 +265,84 @@ int str9x_erase(struct flash_bank_s *bank, int first, int last)
        int i;
        u32 adr;
        u8 status;
+       u8 erase_cmd;
        
        if (bank->target->state != TARGET_HALTED)
        {
+               LOG_ERROR("Target not halted");
                return ERROR_TARGET_NOT_HALTED;
        }
 
+       /* Check if we erase whole bank */
+       if ((first == 0) && (last == (bank->num_sectors - 1)))
+       {
+               /* Optimize to run erase bank command instead of sector */
+               erase_cmd = 0x80;
+       }
+       else
+       {
+               /* Erase sector command */
+               erase_cmd = 0x20;
+       }
+       
        for (i = first; i <= last; i++)
        {
+               int retval;
                adr = bank->base + bank->sectors[i].offset;
                
                /* erase sectors */
-               target_write_u16(target, adr, 0x20);
-               target_write_u16(target, adr, 0xD0);
+               if ((retval=target_write_u16(target, adr, erase_cmd))!=ERROR_OK)
+               {
+                       return retval;
+               }
+               if ((retval=target_write_u16(target, adr, 0xD0))!=ERROR_OK)
+               {
+                       return retval;
+               }
                
                /* get status */
-               target_write_u16(target, adr, 0x70);
-               
-               while (1) {
-                       target_read_u8(target, adr, &status);
+               if ((retval=target_write_u16(target, adr, 0x70))!=ERROR_OK)
+               {
+                       return retval;
+               }
+
+               int timeout;            
+               for (timeout=0; timeout<1000; timeout++) {
+                       if ((retval=target_read_u8(target, adr, &status))!=ERROR_OK)
+                       {
+                               return retval;
+                       }
                        if( status & 0x80 )
                                break;
-                       usleep(1000);
+                       alive_sleep(1);
+               }
+               if (timeout==1000)
+               {
+                       LOG_ERROR("erase timed out");
+                       return ERROR_FAIL;
                }
                
                /* clear status, also clear read array */
-               target_write_u16(target, adr, 0x50);
+               if ((retval=target_write_u16(target, adr, 0x50))!=ERROR_OK)
+               {
+                       return retval;
+               }
                
                /* read array command */
-               target_write_u16(target, adr, 0xFF);
+               if ((retval=target_write_u16(target, adr, 0xFF))!=ERROR_OK)
+               {
+                       return retval;
+               }
                
                if( status & 0x22 )
                {
                        LOG_ERROR("error erasing flash bank, status: 0x%x", status);
                        return ERROR_FLASH_OPERATION_FAILED;
                }
+               
+               /* If we ran erase bank command, we are finished */
+               if (erase_cmd == 0x80)
+                       break;
        }
        
        for (i = first; i <= last; i++)
@@ -288,6 +360,7 @@ int str9x_protect(struct flash_bank_s *bank, int set, int first, int last)
        
        if (bank->target->state != TARGET_HALTED)
        {
+               LOG_ERROR("Target not halted");
                return ERROR_TARGET_NOT_HALTED;
        }
        
@@ -325,7 +398,7 @@ int str9x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 cou
        u32 address = bank->base + offset;
        reg_param_t reg_params[4];
        armv4_5_algorithm_t armv4_5_info;
-       int retval;
+       int retval = ERROR_OK;
        
        u32 str9x_flash_write_code[] = {
                                        /* write:                               */
@@ -397,15 +470,15 @@ int str9x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 cou
 
                if ((retval = target->type->run_algorithm(target, 0, NULL, 4, reg_params, str9x_info->write_algorithm->address, str9x_info->write_algorithm->address + (18 * 4), 10000, &armv4_5_info)) != ERROR_OK)
                {
-                       target_free_working_area(target, source);
-                       target_free_working_area(target, str9x_info->write_algorithm);
                        LOG_ERROR("error executing str9x flash write algorithm");
-                       return ERROR_FLASH_OPERATION_FAILED;
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
                }
        
                if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80)
                {
-                       return ERROR_FLASH_OPERATION_FAILED;
+                       retval = ERROR_FLASH_OPERATION_FAILED;
+                       break;
                }
                
                buffer += thisrun_count * 2;
@@ -421,7 +494,7 @@ int str9x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 cou
        destroy_reg_param(&reg_params[2]);
        destroy_reg_param(&reg_params[3]);
        
-       return ERROR_OK;
+       return retval;
 }
 
 int str9x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
@@ -439,6 +512,7 @@ int str9x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
        
        if (bank->target->state != TARGET_HALTED)
        {
+               LOG_ERROR("Target not halted");
                return ERROR_TARGET_NOT_HALTED;
        }
 
@@ -503,12 +577,19 @@ int str9x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
                
                /* get status command */
                target_write_u16(target, bank_adr, 0x70);
-               
-               while (1) {
+       
+               int timeout;
+               for (timeout=0; timeout<1000; timeout++)
+               {       
                        target_read_u8(target, bank_adr, &status);
                        if( status & 0x80 )
                                break;
-                       usleep(1000);
+                       alive_sleep(1);
+               }
+               if (timeout==1000)
+               {
+                       LOG_ERROR("write timed out");
+                       return ERROR_FAIL;
                }
                
                /* clear status reg and read array */
@@ -546,11 +627,18 @@ int str9x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
                /* query status command */
                target_write_u16(target, bank_adr, 0x70);
                
-               while (1) {
+               int timeout;
+               for (timeout=0; timeout<1000; timeout++)
+               {       
                        target_read_u8(target, bank_adr, &status);
                        if( status & 0x80 )
                                break;
-                       usleep(1000);
+                       alive_sleep(1);
+               }
+               if (timeout==1000)
+               {
+                       LOG_ERROR("write timed out");
+                       return ERROR_FAIL;
                }
                
                /* clear status reg and read array */
@@ -606,6 +694,7 @@ int str9x_handle_flash_config_command(struct command_context_s *cmd_ctx, char *c
        
        if (bank->target->state != TARGET_HALTED)
        {
+               LOG_ERROR("Target not halted");
                return ERROR_TARGET_NOT_HALTED;
        }