Change return value on error.
[fw/openocd] / src / flash / nor / lpc2000.c
index 0caf3e09b80663ba215e57a5c5ed3a10fe7d9464..b4e17e7eabecc2f54d12518f1964fa3fc6a444e6 100644 (file)
 #endif
 
 #include "imp.h"
-#include "lpc2000.h"
 #include <helper/binarybuffer.h>
 #include <target/algorithm.h>
+#include <target/arm_opcodes.h>
 #include <target/armv7m.h>
 
-
-/* flash programming support for NXP LPC17xx and LPC2xxx devices
+/**
+ * @file
+ * flash programming support for NXP LPC17xx and LPC2xxx devices.
+ *
+ * @todo Provide a way to update CCLK after declaring the flash bank.
+ * The value which is correct after chip reset will rarely still work
+ * right after the clocks switch to use the PLL (e.g. 4MHz --> 100 MHz).
+ */
+/*
  * currently supported devices:
  * variant 1 (lpc2000_v1):
  * - 2104 | 5 | 6
  * - 176x (tested with LPC1768)
  */
 
+typedef enum
+{
+       lpc2000_v1,
+       lpc2000_v2,
+       lpc1700
+} lpc2000_variant;
+
+struct lpc2000_flash_bank
+{
+       lpc2000_variant variant;
+       struct working_area *iap_working_area;
+       uint32_t cclk;
+       int cmd51_dst_boundary;
+       int cmd51_can_256b;
+       int cmd51_can_8192b;
+       int calc_checksum;
+       uint32_t cmd51_max_buffer;
+       int checksum_vector;
+};
+
+enum lpc2000_status_codes
+{
+       LPC2000_CMD_SUCCESS = 0,
+       LPC2000_INVALID_COMMAND = 1,
+       LPC2000_SRC_ADDR_ERROR = 2,
+       LPC2000_DST_ADDR_ERROR = 3,
+       LPC2000_SRC_ADDR_NOT_MAPPED = 4,
+       LPC2000_DST_ADDR_NOT_MAPPED = 5,
+       LPC2000_COUNT_ERROR = 6,
+       LPC2000_INVALID_SECTOR = 7,
+       LPC2000_SECTOR_NOT_BLANK = 8,
+       LPC2000_SECTOR_NOT_PREPARED = 9,
+       LPC2000_COMPARE_ERROR = 10,
+       LPC2000_BUSY = 11,
+       LPC2000_PARAM_ERROR = 12,
+       LPC2000_ADDR_ERROR = 13,
+       LPC2000_ADDR_NOT_MAPPED = 14,
+       LPC2000_CMD_NOT_LOCKED = 15,
+       LPC2000_INVALID_CODE = 16,
+       LPC2000_INVALID_BAUD_RATE = 17,
+       LPC2000_INVALID_STOP_BIT = 18,
+       LPC2000_CRP_ENABLED = 19
+};
+
 static int lpc2000_build_sector_list(struct flash_bank *bank)
 {
        struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
@@ -143,10 +194,13 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
                        case 256 * 1024:
                                bank->num_sectors = 15;
                                break;
-                       case 512 * 1024:
                        case 500 * 1024:
                                bank->num_sectors = 27;
                                break;
+                       case 512 * 1024:
+                       case 504 * 1024:
+                               bank->num_sectors = 28;
+                               break;
                        default:
                                LOG_ERROR("BUG: unknown bank->size encountered");
                                exit(-1);
@@ -157,7 +211,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
 
                for (i = 0; i < bank->num_sectors; i++)
                {
-                       if ((i >= 0) && (i < 8))
+                       if (i < 8)
                        {
                                bank->sectors[i].offset = offset;
                                bank->sectors[i].size = 4 * 1024;
@@ -165,7 +219,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
                                bank->sectors[i].is_erased = -1;
                                bank->sectors[i].is_protected = 1;
                        }
-                       if ((i >= 8) && (i < 22))
+                       else if (i < 22)
                        {
                                bank->sectors[i].offset = offset;
                                bank->sectors[i].size = 32 * 1024;
@@ -173,7 +227,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
                                bank->sectors[i].is_erased = -1;
                                bank->sectors[i].is_protected = 1;
                        }
-                       if ((i >= 22) && (i < 27))
+                       else if (i < 28)
                        {
                                bank->sectors[i].offset = offset;
                                bank->sectors[i].size = 4 * 1024;
@@ -263,8 +317,10 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
                switch(lpc2000_info->variant)
                {
                        case lpc1700:
-                               target_buffer_set_u32(target, jump_gate, ARMV7M_T_BX(12));
-                               target_buffer_set_u32(target, jump_gate + 4, ARMV7M_T_B(0xfffffe));
+                               target_buffer_set_u32(target, jump_gate,
+                                               ARMV4_5_T_BX(12));
+                               target_buffer_set_u32(target, jump_gate + 4,
+                                               ARMV5_T_BKPT(0));
                                break;
                        case lpc2000_v1:
                        case lpc2000_v2:
@@ -272,7 +328,7 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
                                target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0));
                                break;
                        default:
-                               LOG_ERROR("BUG: unknown bank->size encountered");
+                               LOG_ERROR("BUG: unknown lpc2000_info->variant encountered");
                                exit(-1);
                }
 
@@ -335,12 +391,12 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
                        init_reg_param(&reg_params[4], "lr", 32, PARAM_OUT);
                        buf_set_u32(reg_params[4].value, 0, 32, (lpc2000_info->iap_working_area->address + 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */
 
-                       target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv7m_info);
+                       target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, 0, 10000, &armv7m_info);
                        break;
                case lpc2000_v1:
                case lpc2000_v2:
                        /* IAP stack */
-                       init_reg_param(&reg_params[3], "r13_svc", 32, PARAM_OUT);
+                       init_reg_param(&reg_params[3], "sp_svc", 32, PARAM_OUT);
                        buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4);
 
                        /* return address */
@@ -354,7 +410,6 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
                        exit(-1);
        }
 
-
        status_code     = target_buffer_get_u32(target, mem_params[1].value);
        result_table[0] = target_buffer_get_u32(target, mem_params[1].value + 0x04);
        result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 0x08);
@@ -426,8 +481,7 @@ FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
 
        if (CMD_ARGC < 8)
        {
-               LOG_WARNING("incomplete flash_bank lpc2000 configuration");
-               return ERROR_FLASH_BANK_INVALID;
+               return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
        lpc2000_info = malloc(sizeof(struct lpc2000_flash_bank));
@@ -583,7 +637,6 @@ static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
        if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum)
        {
                uint32_t checksum = 0;
-               int i;
                for (i = 0; i < 8; i++)
                {
                        LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
@@ -729,7 +782,7 @@ static int lpc2000_protect_check(struct flash_bank *bank)
        return ERROR_OK;
 }
 
-static int lpc2000_info(struct flash_bank *bank, char *buf, int buf_size)
+static int get_lpc2000_info(struct flash_bank *bank, char *buf, int buf_size)
 {
        struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
 
@@ -780,7 +833,7 @@ COMMAND_HANDLER(lpc2000_handle_part_id_command)
 static const struct command_registration lpc2000_exec_command_handlers[] = {
        {
                .name = "part_id",
-               .handler = &lpc2000_handle_part_id_command,
+               .handler = lpc2000_handle_part_id_command,
                .mode = COMMAND_EXEC,
                .help = "print part id of lpc2000 flash bank <num>",
        },
@@ -797,17 +850,16 @@ static const struct command_registration lpc2000_command_handlers[] = {
 };
 
 struct flash_driver lpc2000_flash = {
-               .name = "lpc2000",
-               .commands = lpc2000_command_handlers,
-               .flash_bank_command = &lpc2000_flash_bank_command,
-               .erase = &lpc2000_erase,
-               .protect = &lpc2000_protect,
-               .write = &lpc2000_write,
-               .probe = &lpc2000_probe,
-               .auto_probe = &lpc2000_probe,
-               .erase_check = &lpc2000_erase_check,
-               .protect_check = &lpc2000_protect_check,
-               .info = &lpc2000_info,
-       };
-
-
+       .name = "lpc2000",
+       .commands = lpc2000_command_handlers,
+       .flash_bank_command = lpc2000_flash_bank_command,
+       .erase = lpc2000_erase,
+       .protect = lpc2000_protect,
+       .write = lpc2000_write,
+       .read = default_flash_read,
+       .probe = lpc2000_probe,
+       .auto_probe = lpc2000_probe,
+       .erase_check = lpc2000_erase_check,
+       .protect_check = lpc2000_protect_check,
+       .info = get_lpc2000_info,
+};