XCF (Xilinx platfrom flash) support.
[fw/openocd] / src / flash / nor / core.c
index 21ea05d33782feb96d7934d42fdb4c5bda723532..ab69a328bd8497ed3ad41dc29d7ee2e6e9e9accd 100644 (file)
@@ -16,9 +16,7 @@
  *   GNU General Public License for more details.                          *
  *                                                                         *
  *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -52,10 +50,17 @@ int flash_driver_erase(struct flash_bank *bank, int first, int last)
 int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
 {
        int retval;
+       int num_blocks;
+
+       if (bank->num_prot_blocks)
+               num_blocks = bank->num_prot_blocks;
+       else
+               num_blocks = bank->num_sectors;
+
 
        /* callers may not supply illegal parameters ... */
-       if (first < 0 || first > last || last >= bank->num_sectors) {
-               LOG_ERROR("illegal sector range");
+       if (first < 0 || first > last || last >= num_blocks) {
+               LOG_ERROR("illegal protection block range");
                return ERROR_FAIL;
        }
 
@@ -71,11 +76,11 @@ int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
         * the target could have reset, power cycled, been hot plugged,
         * the application could have run, etc.
         *
-        * Drivers only receive valid sector range.
+        * Drivers only receive valid protection block range.
         */
        retval = bank->driver->protect(bank, set, first, last);
        if (retval != ERROR_OK)
-               LOG_ERROR("failed setting protection for areas %d to %d", first, last);
+               LOG_ERROR("failed setting protection for blocks %d to %d", first, last);
 
        return retval;
 }
@@ -232,6 +237,9 @@ int get_flash_bank_by_addr(struct target *target,
 
        /* cycle through bank list */
        for (c = flash_banks; c; c = c->next) {
+               if (c->target != target)
+                       continue;
+
                int retval;
                retval = c->driver->auto_probe(c);
 
@@ -240,7 +248,7 @@ int get_flash_bank_by_addr(struct target *target,
                        return retval;
                }
                /* check whether address belongs to this flash bank */
-               if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target) {
+               if ((addr >= c->base) && (addr <= c->base + (c->size - 1))) {
                        *result_bank = c;
                        return ERROR_OK;
                }
@@ -287,7 +295,7 @@ static int default_flash_mem_blank_check(struct flash_bank *bank)
                                goto done;
 
                        for (nBytes = 0; nBytes < chunk; nBytes++) {
-                               if (buffer[nBytes] != 0xFF) {
+                               if (buffer[nBytes] != bank->erased_value) {
                                        bank->sectors[i].is_erased = 0;
                                        break;
                                }
@@ -318,12 +326,12 @@ int default_flash_blank_check(struct flash_bank *bank)
                uint32_t address = bank->base + bank->sectors[i].offset;
                uint32_t size = bank->sectors[i].size;
 
-               retval = target_blank_check_memory(target, address, size, &blank);
+               retval = target_blank_check_memory(target, address, size, &blank, bank->erased_value);
                if (retval != ERROR_OK) {
                        fast_check = 0;
                        break;
                }
-               if (blank == 0xFF)
+               if (blank == bank->erased_value)
                        bank->sectors[i].is_erased = 1;
                else
                        bank->sectors[i].is_erased = 0;
@@ -342,8 +350,9 @@ int default_flash_blank_check(struct flash_bank *bank)
  * and address.  Maps an address range to a set of sectors, and issues
  * the callback() on that set ... e.g. to erase or unprotect its members.
  *
- * (Note a current bad assumption:  that protection operates on the same
- * size sectors as erase operations use.)
+ * Parameter iterate_protect_blocks switches iteration of protect block
+ * instead of erase sectors. If there is no protect blocks array, sectors
+ * are used in iteration, so compatibility for old flash drivers is retained.
  *
  * The "pad_reason" parameter is a kind of boolean:  when it's NULL, the
  * range must fit those sectors exactly.  This is clearly safe; it can't
@@ -354,13 +363,16 @@ int default_flash_blank_check(struct flash_bank *bank)
  */
 static int flash_iterate_address_range_inner(struct target *target,
        char *pad_reason, uint32_t addr, uint32_t length,
+       bool iterate_protect_blocks,
        int (*callback)(struct flash_bank *bank, int first, int last))
 {
        struct flash_bank *c;
+       struct flash_sector *block_array;
        uint32_t last_addr = addr + length;     /* first address AFTER end */
        int first = -1;
        int last = -1;
        int i;
+       int num_blocks;
 
        int retval = get_flash_bank_by_addr(target, addr, true, &c);
        if (retval != ERROR_OK)
@@ -387,13 +399,21 @@ static int flash_iterate_address_range_inner(struct target *target,
                return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
        }
 
-       /** @todo: handle erasures that cross into adjacent banks */
-
        addr -= c->base;
        last_addr -= c->base;
 
-       for (i = 0; i < c->num_sectors; i++) {
-               struct flash_sector *f = c->sectors + i;
+       if (iterate_protect_blocks && c->prot_blocks && c->num_prot_blocks) {
+               block_array = c->prot_blocks;
+               num_blocks = c->num_prot_blocks;
+       } else {
+               block_array = c->sectors;
+               num_blocks = c->num_sectors;
+               iterate_protect_blocks = false;
+       }
+
+
+       for (i = 0; i < num_blocks; i++) {
+               struct flash_sector *f = &block_array[i];
                uint32_t end = f->offset + f->size;
 
                /* start only on a sector boundary */
@@ -471,6 +491,7 @@ static int flash_iterate_address_range_inner(struct target *target,
  */
 static int flash_iterate_address_range(struct target *target,
        char *pad_reason, uint32_t addr, uint32_t length,
+       bool iterate_protect_blocks,
        int (*callback)(struct flash_bank *bank, int first, int last))
 {
        struct flash_bank *c;
@@ -490,6 +511,7 @@ static int flash_iterate_address_range(struct target *target,
                }
                retval = flash_iterate_address_range_inner(target,
                                pad_reason, addr, cur_length,
+                               iterate_protect_blocks,
                                callback);
                if (retval != ERROR_OK)
                        break;
@@ -505,7 +527,7 @@ int flash_erase_address_range(struct target *target,
        bool pad, uint32_t addr, uint32_t length)
 {
        return flash_iterate_address_range(target, pad ? "erase" : NULL,
-               addr, length, &flash_driver_erase);
+               addr, length, false, &flash_driver_erase);
 }
 
 static int flash_driver_unprotect(struct flash_bank *bank, int first, int last)
@@ -520,7 +542,7 @@ int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t le
         * and doesn't restore it.
         */
        return flash_iterate_address_range(target, "unprotect",
-               addr, length, &flash_driver_unprotect);
+               addr, length, true, &flash_driver_unprotect);
 }
 
 static int compare_section(const void *a, const void *b)
@@ -595,7 +617,7 @@ int flash_write_unlock(struct target *target, struct image *image,
                if (retval != ERROR_OK)
                        goto done;
                if (c == NULL) {
-                       LOG_WARNING("no flash bank found for address %x", run_address);
+                       LOG_WARNING("no flash bank found for address %" PRIx32, run_address);
                        section++;      /* and skip it */
                        section_offset = 0;
                        continue;
@@ -710,7 +732,7 @@ int flash_write_unlock(struct target *target, struct image *image,
 
                        /* see if we need to pad the section */
                        while (padding[section]--)
-                               (buffer + buffer_size)[size_read++] = 0xff;
+                               (buffer + buffer_size)[size_read++] = c->default_padded_value;
 
                        buffer_size += size_read;
                        section_offset += size_read;
@@ -761,3 +783,22 @@ int flash_write(struct target *target, struct image *image,
 {
        return flash_write_unlock(target, image, written, erase, false);
 }
+
+struct flash_sector *alloc_block_array(uint32_t offset, uint32_t size, int num_blocks)
+{
+       int i;
+
+       struct flash_sector *array = calloc(num_blocks, sizeof(struct flash_sector));
+       if (array == NULL)
+               return NULL;
+
+       for (i = 0; i < num_blocks; i++) {
+               array[i].offset = offset;
+               array[i].size = size;
+               array[i].is_erased = -1;
+               array[i].is_protected = -1;
+               offset += size;
+       }
+
+       return array;
+}