openocd: fix SPDX tag format for files .c
[fw/openocd] / src / flash / nor / stm32lx.c
index fdfaad4cf7e8102f7593312bf471b39059512129..42b52c5c2b09a3d9cd2d419c2d2df9dd8493a95e 100644 (file)
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
 /***************************************************************************
  *   Copyright (C) 2005 by Dominic Rath                                    *
  *   Dominic.Rath@gmx.de                                                   *
@@ -7,19 +9,6 @@
  *                                                                         *
  *   Copyright (C) 2011 by Clement Burin des Roziers                       *
  *   clement.burin-des-roziers@hikob.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, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -128,7 +117,7 @@ struct stm32lx_part_info {
 };
 
 struct stm32lx_flash_bank {
-       int probed;
+       bool probed;
        uint32_t idcode;
        uint32_t user_bank_size;
        uint32_t flash_base;
@@ -146,13 +135,13 @@ static const struct stm32lx_rev stm32_425_revs[] = {
        { 0x1000, "A" }, { 0x2000, "B" }, { 0x2008, "Y" },
 };
 static const struct stm32lx_rev stm32_427_revs[] = {
-       { 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" },
+       { 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" }, { 0x10f8, "V" },
 };
 static const struct stm32lx_rev stm32_429_revs[] = {
        { 0x1000, "A" }, { 0x1018, "Z" },
 };
 static const struct stm32lx_rev stm32_436_revs[] = {
-       { 0x1000, "A" }, { 0x1008, "Z" }, { 0x1018, "Y" },
+       { 0x1000, "A" }, { 0x1008, "Z" }, { 0x1018, "Y" }, { 0x1038, "X" },
 };
 static const struct stm32lx_rev stm32_437_revs[] = {
        { 0x1000, "A" },
@@ -290,14 +279,14 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command)
        stm32lx_info = calloc(1, sizeof(*stm32lx_info));
 
        /* Check allocation */
-       if (stm32lx_info == NULL) {
+       if (!stm32lx_info) {
                LOG_ERROR("failed to allocate bank structure");
                return ERROR_FAIL;
        }
 
        bank->driver_priv = stm32lx_info;
 
-       stm32lx_info->probed = 0;
+       stm32lx_info->probed = false;
        stm32lx_info->user_bank_size = bank->size;
 
        /* the stm32l erased value is 0x00 */
@@ -308,26 +297,19 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command)
 
 COMMAND_HANDLER(stm32lx_handle_mass_erase_command)
 {
-       int i;
-
        if (CMD_ARGC < 1)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        struct flash_bank *bank;
        int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
+       if (retval != ERROR_OK)
                return retval;
 
        retval = stm32lx_mass_erase(bank);
-       if (retval == ERROR_OK) {
-               /* set all sectors as erased */
-               for (i = 0; i < bank->num_sectors; i++)
-                       bank->sectors[i].is_erased = 1;
-
-               command_print(CMD_CTX, "stm32lx mass erase complete");
-       } else {
-               command_print(CMD_CTX, "stm32lx mass erase failed");
-       }
+       if (retval == ERROR_OK)
+               command_print(CMD, "stm32lx mass erase complete");
+       else
+               command_print(CMD, "stm32lx mass erase failed");
 
        return retval;
 }
@@ -339,15 +321,15 @@ COMMAND_HANDLER(stm32lx_handle_lock_command)
 
        struct flash_bank *bank;
        int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
+       if (retval != ERROR_OK)
                return retval;
 
        retval = stm32lx_lock(bank);
 
        if (retval == ERROR_OK)
-               command_print(CMD_CTX, "STM32Lx locked, takes effect after power cycle.");
+               command_print(CMD, "STM32Lx locked, takes effect after power cycle.");
        else
-               command_print(CMD_CTX, "STM32Lx lock failed");
+               command_print(CMD, "STM32Lx lock failed");
 
        return retval;
 }
@@ -359,15 +341,15 @@ COMMAND_HANDLER(stm32lx_handle_unlock_command)
 
        struct flash_bank *bank;
        int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
-       if (ERROR_OK != retval)
+       if (retval != ERROR_OK)
                return retval;
 
        retval = stm32lx_unlock(bank);
 
        if (retval == ERROR_OK)
-               command_print(CMD_CTX, "STM32Lx unlocked, takes effect after power cycle.");
+               command_print(CMD, "STM32Lx unlocked, takes effect after power cycle.");
        else
-               command_print(CMD_CTX, "STM32Lx unlock failed");
+               command_print(CMD, "STM32Lx unlock failed");
 
        return retval;
 }
@@ -389,7 +371,7 @@ static int stm32lx_protect_check(struct flash_bank *bank)
        if (retval != ERROR_OK)
                return retval;
 
-       for (int i = 0; i < bank->num_sectors; i++) {
+       for (unsigned int i = 0; i < bank->num_sectors; i++) {
                if (wrpr & (1 << i))
                        bank->sectors[i].is_protected = 1;
                else
@@ -398,7 +380,8 @@ static int stm32lx_protect_check(struct flash_bank *bank)
        return ERROR_OK;
 }
 
-static int stm32lx_erase(struct flash_bank *bank, int first, int last)
+static int stm32lx_erase(struct flash_bank *bank, unsigned int first,
+               unsigned int last)
 {
        int retval;
 
@@ -415,7 +398,7 @@ static int stm32lx_erase(struct flash_bank *bank, int first, int last)
        /*
         * Loop over the selected sectors and erase them
         */
-       for (int i = first; i <= last; i++) {
+       for (unsigned int i = first; i <= last; i++) {
                retval = stm32lx_erase_sector(bank, i);
                if (retval != ERROR_OK)
                        return retval;
@@ -424,13 +407,6 @@ static int stm32lx_erase(struct flash_bank *bank, int first, int last)
        return ERROR_OK;
 }
 
-static int stm32lx_protect(struct flash_bank *bank, int set, int first,
-               int last)
-{
-       LOG_WARNING("protection of the STM32L flash is not implemented");
-       return ERROR_OK;
-}
-
 static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buffer,
                uint32_t offset, uint32_t count)
 {
@@ -438,25 +414,27 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
        struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
 
        uint32_t hp_nb = stm32lx_info->part_info.page_size / 2;
-       uint32_t buffer_size = 16384;
+       uint32_t buffer_size = (16384 / hp_nb) * hp_nb; /* must be multiple of hp_nb */
        struct working_area *write_algorithm;
        struct working_area *source;
        uint32_t address = bank->base + offset;
 
-       struct reg_param reg_params[3];
+       struct reg_param reg_params[5];
        struct armv7m_algorithm armv7m_info;
 
        int retval = ERROR_OK;
 
-       /* see contib/loaders/flash/stm32lx.S for src */
-
        static const uint8_t stm32lx_flash_write_code[] = {
-                       0x92, 0x00, 0x8A, 0x18, 0x01, 0xE0, 0x08, 0xC9, 0x08, 0xC0, 0x91, 0x42, 0xFB, 0xD1, 0x00, 0xBE
+#include "../../../contrib/loaders/flash/stm32/stm32lx.inc"
        };
 
        /* Make sure we're performing a half-page aligned write. */
+       if (offset % hp_nb) {
+               LOG_ERROR("The offset must be %" PRIu32 "B-aligned but it is %" PRIi32 "B)", hp_nb, offset);
+               return ERROR_FAIL;
+       }
        if (count % hp_nb) {
-               LOG_ERROR("The byte count must be %" PRIu32 "B-aligned but count is %" PRIi32 "B)", hp_nb, count);
+               LOG_ERROR("The byte count must be %" PRIu32 "B-aligned but count is %" PRIu32 "B)", hp_nb, count);
                return ERROR_FAIL;
        }
 
@@ -491,6 +469,9 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
 
                        LOG_WARNING("no large enough working area available, can't do block memory writes");
                        return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               } else {
+                       /* Make sure we're still asking for an integral number of half-pages */
+                       buffer_size -= buffer_size % hp_nb;
                }
        }
 
@@ -499,6 +480,8 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
        init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
        init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
        init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
+       init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);
 
        /* Enable half-page write */
        retval = stm32lx_enable_write_half_page(bank);
@@ -509,11 +492,13 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
                destroy_reg_param(&reg_params[0]);
                destroy_reg_param(&reg_params[1]);
                destroy_reg_param(&reg_params[2]);
+               destroy_reg_param(&reg_params[3]);
+               destroy_reg_param(&reg_params[4]);
                return retval;
        }
 
        struct armv7m_common *armv7m = target_to_armv7m(target);
-       if (armv7m == NULL) {
+       if (!armv7m) {
 
                /* something is very wrong if armv7m is NULL */
                LOG_ERROR("unable to get armv7m target");
@@ -539,12 +524,16 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
                buf_set_u32(reg_params[0].value, 0, 32, address);
                /* The source address of the copy (R1) */
                buf_set_u32(reg_params[1].value, 0, 32, source->address);
-               /* The length of the copy (R2) */
-               buf_set_u32(reg_params[2].value, 0, 32, this_count / 4);
+               /* The number of half pages to copy (R2) */
+               buf_set_u32(reg_params[2].value, 0, 32, this_count / hp_nb);
+               /* The size in byes of a half page (R3) */
+               buf_set_u32(reg_params[3].value, 0, 32, hp_nb);
+               /* The flash base address (R4) */
+               buf_set_u32(reg_params[4].value, 0, 32, stm32lx_info->flash_base);
 
                /* 5: Execute the bunch of code */
-               retval = target_run_algorithm(target, 0, NULL, sizeof(reg_params)
-                               / sizeof(*reg_params), reg_params,
+               retval = target_run_algorithm(target, 0, NULL,
+                               ARRAY_SIZE(reg_params), reg_params,
                                write_algorithm->address, 0, 10000, &armv7m_info);
                if (retval != ERROR_OK)
                        break;
@@ -608,6 +597,8 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
        destroy_reg_param(&reg_params[0]);
        destroy_reg_param(&reg_params[1]);
        destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       destroy_reg_param(&reg_params[4]);
 
        return retval;
 }
@@ -639,7 +630,7 @@ static int stm32lx_write(struct flash_bank *bank, const uint8_t *buffer,
        if (retval != ERROR_OK)
                return retval;
 
-       /* first we need to write any unaligned head bytes upto
+       /* first we need to write any unaligned head bytes up to
         * the next 128 byte page */
 
        if (offset % hp_nb)
@@ -728,7 +719,7 @@ static int stm32lx_read_id_code(struct target *target, uint32_t *id)
 {
        struct armv7m_common *armv7m = target_to_armv7m(target);
        int retval;
-       if (armv7m->arm.is_armv6m == true)
+       if (armv7m->arm.arch == ARM_ARCH_V6M)
                retval = target_read_u32(target, DBGMCU_IDCODE_L0, id);
        else
        /* read stm32 device id register */
@@ -740,14 +731,13 @@ static int stm32lx_probe(struct flash_bank *bank)
 {
        struct target *target = bank->target;
        struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
-       int i;
        uint16_t flash_size_in_kb;
        uint32_t device_id;
        uint32_t base_address = FLASH_BANK0_ADDRESS;
        uint32_t second_bank_base;
        unsigned int n;
 
-       stm32lx_info->probed = 0;
+       stm32lx_info->probed = false;
 
        int retval = stm32lx_read_id_code(bank->target, &device_id);
        if (retval != ERROR_OK)
@@ -765,7 +755,7 @@ static int stm32lx_probe(struct flash_bank *bank)
        }
 
        if (n == ARRAY_SIZE(stm32lx_parts)) {
-               LOG_WARNING("Cannot identify target as a STM32L family.");
+               LOG_ERROR("Cannot identify target as an STM32 L0 or L1 family device.");
                return ERROR_FAIL;
        } else {
                LOG_INFO("Device: %s", stm32lx_info->part_info.device_str);
@@ -825,12 +815,13 @@ static int stm32lx_probe(struct flash_bank *bank)
                        /* This is the first bank */
                        flash_size_in_kb = stm32lx_info->part_info.first_bank_size_kb;
                } else {
-                       LOG_WARNING("STM32L flash bank base address config is incorrect."
-                                   " 0x%" PRIx32 " but should rather be 0x%" PRIx32 " or 0x%" PRIx32,
+                       LOG_WARNING("STM32L flash bank base address config is incorrect. "
+                                       TARGET_ADDR_FMT " but should rather be 0x%" PRIx32
+                                       " or 0x%" PRIx32,
                                                bank->base, base_address, second_bank_base);
                        return ERROR_FAIL;
                }
-               LOG_INFO("STM32L flash has dual banks. Bank (%d) size is %dkb, base address is 0x%" PRIx32,
+               LOG_INFO("STM32L flash has dual banks. Bank (%u) size is %dkb, base address is 0x%" PRIx32,
                                bank->bank_number, flash_size_in_kb, base_address);
        } else {
                LOG_INFO("STM32L flash size is %dkb, base address is 0x%" PRIx32, flash_size_in_kb, base_address);
@@ -844,30 +835,27 @@ static int stm32lx_probe(struct flash_bank *bank)
        }
 
        /* calculate numbers of sectors (4kB per sector) */
-       int num_sectors = (flash_size_in_kb * 1024) / FLASH_SECTOR_SIZE;
+       unsigned int num_sectors = (flash_size_in_kb * 1024) / FLASH_SECTOR_SIZE;
 
-       if (bank->sectors) {
-               free(bank->sectors);
-               bank->sectors = NULL;
-       }
+       free(bank->sectors);
 
        bank->size = flash_size_in_kb * 1024;
        bank->base = base_address;
        bank->num_sectors = num_sectors;
        bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
-       if (bank->sectors == NULL) {
+       if (!bank->sectors) {
                LOG_ERROR("failed to allocate bank sectors");
                return ERROR_FAIL;
        }
 
-       for (i = 0; i < num_sectors; i++) {
+       for (unsigned int i = 0; i < num_sectors; i++) {
                bank->sectors[i].offset = i * FLASH_SECTOR_SIZE;
                bank->sectors[i].size = FLASH_SECTOR_SIZE;
                bank->sectors[i].is_erased = -1;
-               bank->sectors[i].is_protected = 1;
+               bank->sectors[i].is_protected = -1;
        }
 
-       stm32lx_info->probed = 1;
+       stm32lx_info->probed = true;
 
        return ERROR_OK;
 }
@@ -883,7 +871,7 @@ static int stm32lx_auto_probe(struct flash_bank *bank)
 }
 
 /* This method must return a string displaying information about the bank */
-static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size)
+static int stm32lx_get_info(struct flash_bank *bank, struct command_invocation *cmd)
 {
        struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
        const struct stm32lx_part_info *info = &stm32lx_info->part_info;
@@ -893,8 +881,7 @@ static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size)
        if (!stm32lx_info->probed) {
                int retval = stm32lx_probe(bank);
                if (retval != ERROR_OK) {
-                       snprintf(buf, buf_size,
-                               "Unable to find bank information.");
+                       command_print_sameline(cmd, "Unable to find bank information.");
                        return retval;
                }
        }
@@ -903,14 +890,10 @@ static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size)
                if (rev_id == info->revs[i].rev)
                        rev_str = info->revs[i].str;
 
-       if (rev_str != NULL) {
-               snprintf(buf, buf_size,
-                       "%s - Rev: %s",
-                       info->device_str, rev_str);
+       if (rev_str) {
+               command_print_sameline(cmd, "%s - Rev: %s", info->device_str, rev_str);
        } else {
-               snprintf(buf, buf_size,
-                       "%s - Rev: unknown (0x%04x)",
-                       info->device_str, rev_id);
+               command_print_sameline(cmd, "%s - Rev: unknown (0x%04x)", info->device_str, rev_id);
        }
 
        return ERROR_OK;
@@ -952,12 +935,11 @@ static const struct command_registration stm32lx_command_handlers[] = {
        COMMAND_REGISTRATION_DONE
 };
 
-struct flash_driver stm32lx_flash = {
+const struct flash_driver stm32lx_flash = {
                .name = "stm32lx",
                .commands = stm32lx_command_handlers,
                .flash_bank_command = stm32lx_flash_bank_command,
                .erase = stm32lx_erase,
-               .protect = stm32lx_protect,
                .write = stm32lx_write,
                .read = default_flash_read,
                .probe = stm32lx_probe,
@@ -965,6 +947,7 @@ struct flash_driver stm32lx_flash = {
                .erase_check = default_flash_blank_check,
                .protect_check = stm32lx_protect_check,
                .info = stm32lx_get_info,
+               .free_driver_priv = default_flash_free_driver_priv,
 };
 
 /* Static methods implementation */