openocd: fix SPDX tag format for files .c
[fw/openocd] / src / flash / nor / mdr.c
index 3ecee1c84f779f0dc1e7fed03022884ab208815d..f6285de5b85cb8a3279863839e189e2b3f0acb46 100644 (file)
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
 /***************************************************************************
  *   Copyright (C) 2005 by Dominic Rath                                    *
  *   Dominic.Rath@gmx.de                                                   *
  *                                                                         *
  *   Copyright (C) 2013 by Paul Fertser                                    *
  *   fercerpav@gmail.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     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   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.           *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -64,7 +51,7 @@
 #define KEY            0x8AAA5551
 
 struct mdr_flash_bank {
-       int probed;
+       bool probed;
        unsigned int mem_type;
        unsigned int page_count;
        unsigned int sec_count;
@@ -81,18 +68,13 @@ FLASH_BANK_COMMAND_HANDLER(mdr_flash_bank_command)
        mdr_info = malloc(sizeof(struct mdr_flash_bank));
 
        bank->driver_priv = mdr_info;
-       mdr_info->probed = 0;
+       mdr_info->probed = false;
        COMMAND_PARSE_NUMBER(uint, CMD_ARGV[6], mdr_info->mem_type);
        COMMAND_PARSE_NUMBER(uint, CMD_ARGV[7], mdr_info->page_count);
        COMMAND_PARSE_NUMBER(uint, CMD_ARGV[8], mdr_info->sec_count);
        return ERROR_OK;
 }
 
-static int mdr_protect_check(struct flash_bank *bank)
-{
-       return ERROR_OK;
-}
-
 static int mdr_mass_erase(struct flash_bank *bank)
 {
        struct target *target = bank->target;
@@ -131,11 +113,12 @@ static int mdr_mass_erase(struct flash_bank *bank)
        return retval;
 }
 
-static int mdr_erase(struct flash_bank *bank, int first, int last)
+static int mdr_erase(struct flash_bank *bank, unsigned int first,
+               unsigned int last)
 {
        struct target *target = bank->target;
        struct mdr_flash_bank *mdr_info = bank->driver_priv;
-       int i, retval, retval2;
+       int retval, retval2;
        unsigned int j;
        uint32_t flash_cmd, cur_per_clock;
 
@@ -159,7 +142,7 @@ static int mdr_erase(struct flash_bank *bank, int first, int last)
 
        retval = target_write_u32(target, FLASH_KEY, KEY);
        if (retval != ERROR_OK)
-               goto reset_pg_and_lock;
+               return retval;
 
        retval = target_read_u32(target, FLASH_CMD, &flash_cmd);
        if (retval != ERROR_OK)
@@ -173,13 +156,14 @@ static int mdr_erase(struct flash_bank *bank, int first, int last)
        if (retval != ERROR_OK)
                goto reset_pg_and_lock;
 
-       if ((first == 0) && (last == (bank->num_sectors - 1))) {
+       if ((first == 0) && (last == (bank->num_sectors - 1)) &&
+               !mdr_info->mem_type) {
                retval = mdr_mass_erase(bank);
                goto reset_pg_and_lock;
        }
 
        unsigned int page_size = bank->size / mdr_info->page_count;
-       for (i = first; i <= last; i++) {
+       for (unsigned int i = first; i <= last; i++) {
                for (j = 0; j < mdr_info->sec_count; j++) {
                        retval = target_write_u32(target, FLASH_ADR, (i * page_size) | (j << 2));
                        if (retval != ERROR_OK)
@@ -202,7 +186,6 @@ static int mdr_erase(struct flash_bank *bank, int first, int last)
                        if (retval != ERROR_OK)
                                goto reset_pg_and_lock;
                }
-               bank->sectors[i].is_erased = 1;
        }
 
 reset_pg_and_lock:
@@ -218,12 +201,7 @@ reset_pg_and_lock:
        return retval;
 }
 
-static int mdr_protect(struct flash_bank *bank, int set, int first, int last)
-{
-       return ERROR_OK;
-}
-
-static int mdr_write_block(struct flash_bank *bank, uint8_t *buffer,
+static int mdr_write_block(struct flash_bank *bank, const uint8_t *buffer,
                uint32_t offset, uint32_t count)
 {
        struct target *target = bank->target;
@@ -255,7 +233,7 @@ static int mdr_write_block(struct flash_bank *bank, uint8_t *buffer,
                        &write_algorithm) != ERROR_OK) {
                LOG_WARNING("no working area available, can't do block memory writes");
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-       };
+       }
 
        retval = target_write_buffer(target, write_algorithm->address,
                        sizeof(mdr32fx_flash_write_code), mdr32fx_flash_write_code);
@@ -274,7 +252,7 @@ static int mdr_write_block(struct flash_bank *bank, uint8_t *buffer,
                        LOG_WARNING("no large enough working area available, can't do block memory writes");
                        return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
                }
-       };
+       }
 
        init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */
        init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);    /* count (32bit) */
@@ -314,7 +292,7 @@ static int mdr_write_block(struct flash_bank *bank, uint8_t *buffer,
        return retval;
 }
 
-static int mdr_write(struct flash_bank *bank, uint8_t *buffer,
+static int mdr_write(struct flash_bank *bank, const uint8_t *buffer,
                uint32_t offset, uint32_t count)
 {
        struct target *target = bank->target;
@@ -338,14 +316,14 @@ static int mdr_write(struct flash_bank *bank, uint8_t *buffer,
        int rem = count % 4;
        if (rem) {
                new_buffer = malloc(count + rem);
-               if (new_buffer == NULL) {
+               if (!new_buffer) {
                        LOG_ERROR("odd number of bytes to write and no memory for padding buffer");
                        return ERROR_FAIL;
                }
                LOG_INFO("odd number of bytes to write, padding with 0xff");
                buffer = memcpy(new_buffer, buffer, count);
                while (rem--)
-                       buffer[count++] = 0xff;
+                       new_buffer[count++] = 0xff;
        }
 
        uint32_t flash_cmd, cur_per_clock;
@@ -353,21 +331,22 @@ static int mdr_write(struct flash_bank *bank, uint8_t *buffer,
 
        retval = target_read_u32(target, MD_PER_CLOCK, &cur_per_clock);
        if (retval != ERROR_OK)
-               return retval;
+               goto free_buffer;
 
        if (!(cur_per_clock & MD_PER_CLOCK_RST_CLK)) {
                /* Something's very wrong if the RST_CLK module is not clocked */
                LOG_ERROR("Target needs reset before flash operations");
-               return ERROR_FLASH_OPERATION_FAILED;
+               retval = ERROR_FLASH_OPERATION_FAILED;
+               goto free_buffer;
        }
 
        retval = target_write_u32(target, MD_PER_CLOCK, cur_per_clock | MD_PER_CLOCK_EEPROM);
        if (retval != ERROR_OK)
-               return retval;
+               goto free_buffer;
 
        retval = target_write_u32(target, FLASH_KEY, KEY);
        if (retval != ERROR_OK)
-               goto reset_pg_and_lock;
+               goto free_buffer;
 
        retval = target_read_u32(target, FLASH_CMD, &flash_cmd);
        if (retval != ERROR_OK)
@@ -466,9 +445,110 @@ reset_pg_and_lock:
        if (retval == ERROR_OK)
                retval = retval2;
 
-       if (new_buffer)
-               free(new_buffer);
+free_buffer:
+       free(new_buffer);
+
+       /* read some bytes bytes to flush buffer in flash accelerator.
+        * See errata for 1986VE1T and 1986VE3. Error 0007 */
+       if ((retval == ERROR_OK) && (!mdr_info->mem_type)) {
+               uint32_t tmp;
+               target_checksum_memory(bank->target, bank->base, 64, &tmp);
+       }
+
+       return retval;
+}
+
+static int mdr_read(struct flash_bank *bank, uint8_t *buffer,
+                   uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       struct mdr_flash_bank *mdr_info = bank->driver_priv;
+       int retval, retval2;
+
+       if (!mdr_info->mem_type)
+               return default_flash_read(bank, buffer, offset, count);
+
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (offset & 0x3) {
+               LOG_ERROR("offset 0x%" PRIx32 " breaks required 4-byte alignment", offset);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       if (count & 0x3) {
+               LOG_ERROR("count 0x%" PRIx32 " breaks required 4-byte alignment", count);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       uint32_t flash_cmd, cur_per_clock;
+
+       retval = target_read_u32(target, MD_PER_CLOCK, &cur_per_clock);
+       if (retval != ERROR_OK)
+               goto err;
+
+       if (!(cur_per_clock & MD_PER_CLOCK_RST_CLK)) {
+               /* Something's very wrong if the RST_CLK module is not clocked */
+               LOG_ERROR("Target needs reset before flash operations");
+               retval = ERROR_FLASH_OPERATION_FAILED;
+               goto err;
+       }
+
+       retval = target_write_u32(target, MD_PER_CLOCK, cur_per_clock | MD_PER_CLOCK_EEPROM);
+       if (retval != ERROR_OK)
+               goto err;
+
+       retval = target_write_u32(target, FLASH_KEY, KEY);
+       if (retval != ERROR_OK)
+               goto err;
+
+       retval = target_read_u32(target, FLASH_CMD, &flash_cmd);
+       if (retval != ERROR_OK)
+               goto err_lock;
+
+       /* Switch on register access */
+       flash_cmd = (flash_cmd & FLASH_DELAY_MASK) | FLASH_CON | FLASH_IFREN;
+       retval = target_write_u32(target, FLASH_CMD, flash_cmd);
+       if (retval != ERROR_OK)
+               goto reset_pg_and_lock;
+
+       for (uint32_t i = 0; i < count; i += 4) {
+               retval = target_write_u32(target, FLASH_ADR, offset + i);
+               if (retval != ERROR_OK)
+                       goto reset_pg_and_lock;
+
+               retval = target_write_u32(target, FLASH_CMD, flash_cmd |
+                                         FLASH_XE | FLASH_YE | FLASH_SE);
+               if (retval != ERROR_OK)
+                       goto reset_pg_and_lock;
+
+               uint32_t buf;
+               retval = target_read_u32(target, FLASH_DO, &buf);
+               if (retval != ERROR_OK)
+                       goto reset_pg_and_lock;
+
+               buf_set_u32(buffer, i * 8, 32, buf);
+
+               retval = target_write_u32(target, FLASH_CMD, flash_cmd);
+               if (retval != ERROR_OK)
+                       goto reset_pg_and_lock;
+
+       }
+
+reset_pg_and_lock:
+       flash_cmd &= FLASH_DELAY_MASK;
+       retval2 = target_write_u32(target, FLASH_CMD, flash_cmd);
+       if (retval == ERROR_OK)
+               retval = retval2;
+
+err_lock:
+       retval2 = target_write_u32(target, FLASH_KEY, 0);
+       if (retval == ERROR_OK)
+               retval = retval2;
 
+err:
        return retval;
 }
 
@@ -480,6 +560,8 @@ static int mdr_probe(struct flash_bank *bank)
        page_count = mdr_info->page_count;
        page_size = bank->size / page_count;
 
+       free(bank->sectors);
+
        bank->num_sectors = page_count;
        bank->sectors = malloc(sizeof(struct flash_sector) * page_count);
 
@@ -490,7 +572,7 @@ static int mdr_probe(struct flash_bank *bank)
                bank->sectors[i].is_protected = 0;
        }
 
-       mdr_info->probed = 1;
+       mdr_info->probed = true;
 
        return ERROR_OK;
 }
@@ -503,25 +585,26 @@ static int mdr_auto_probe(struct flash_bank *bank)
        return mdr_probe(bank);
 }
 
-static int get_mdr_info(struct flash_bank *bank, char *buf, int buf_size)
+static int get_mdr_info(struct flash_bank *bank, struct command_invocation *cmd)
 {
        struct mdr_flash_bank *mdr_info = bank->driver_priv;
-       snprintf(buf, buf_size, "MDR32Fx - %s",
-                mdr_info->mem_type ? "info memory" : "main memory");
+       command_print_sameline(cmd, "MDR32Fx - %s",
+                       mdr_info->mem_type ? "info memory" : "main memory");
 
        return ERROR_OK;
 }
 
-struct flash_driver mdr_flash = {
+const struct flash_driver mdr_flash = {
        .name = "mdr",
+       .usage = "flash bank <name> mdr <base> <size> 0 0 <target#> <type> <page_count> <sec_count>\n"
+       "<type>: 0 for main memory, 1 for info memory",
        .flash_bank_command = mdr_flash_bank_command,
        .erase = mdr_erase,
-       .protect = mdr_protect,
        .write = mdr_write,
-       .read = default_flash_read,
+       .read = mdr_read,
        .probe = mdr_probe,
        .auto_probe = mdr_auto_probe,
        .erase_check = default_flash_blank_check,
-       .protect_check = mdr_protect_check,
        .info = get_mdr_info,
+       .free_driver_priv = default_flash_free_driver_priv,
 };