Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.

Upstream: https://github.com/ARMmbed/DAPLink

Committer:
Pawel Zarembski
Date:
Tue Apr 07 12:55:42 2020 +0200
Revision:
0:01f31e923fe2
hani: DAPLink with reset workaround

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Pawel Zarembski 0:01f31e923fe2 1 /**
Pawel Zarembski 0:01f31e923fe2 2 * @file iap_flash_intf.c
Pawel Zarembski 0:01f31e923fe2 3 * @brief Implementation of flash_intf.h
Pawel Zarembski 0:01f31e923fe2 4 *
Pawel Zarembski 0:01f31e923fe2 5 * DAPLink Interface Firmware
Pawel Zarembski 0:01f31e923fe2 6 * Copyright (c) 2009-2019, ARM Limited, All Rights Reserved
Pawel Zarembski 0:01f31e923fe2 7 * SPDX-License-Identifier: Apache-2.0
Pawel Zarembski 0:01f31e923fe2 8 *
Pawel Zarembski 0:01f31e923fe2 9 * Licensed under the Apache License, Version 2.0 (the "License"); you may
Pawel Zarembski 0:01f31e923fe2 10 * not use this file except in compliance with the License.
Pawel Zarembski 0:01f31e923fe2 11 * You may obtain a copy of the License at
Pawel Zarembski 0:01f31e923fe2 12 *
Pawel Zarembski 0:01f31e923fe2 13 * http://www.apache.org/licenses/LICENSE-2.0
Pawel Zarembski 0:01f31e923fe2 14 *
Pawel Zarembski 0:01f31e923fe2 15 * Unless required by applicable law or agreed to in writing, software
Pawel Zarembski 0:01f31e923fe2 16 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
Pawel Zarembski 0:01f31e923fe2 17 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Pawel Zarembski 0:01f31e923fe2 18 * See the License for the specific language governing permissions and
Pawel Zarembski 0:01f31e923fe2 19 * limitations under the License.
Pawel Zarembski 0:01f31e923fe2 20 */
Pawel Zarembski 0:01f31e923fe2 21
Pawel Zarembski 0:01f31e923fe2 22 #include <string.h>
Pawel Zarembski 0:01f31e923fe2 23
Pawel Zarembski 0:01f31e923fe2 24 #include "daplink.h"
Pawel Zarembski 0:01f31e923fe2 25 #include "flash_intf.h"
Pawel Zarembski 0:01f31e923fe2 26 #include "util.h"
Pawel Zarembski 0:01f31e923fe2 27 #include "flash_hal.h"
Pawel Zarembski 0:01f31e923fe2 28 #include "FlashPrg.h"
Pawel Zarembski 0:01f31e923fe2 29 #include "compiler.h"
Pawel Zarembski 0:01f31e923fe2 30 #include "crc.h"
Pawel Zarembski 0:01f31e923fe2 31 #include "info.h"
Pawel Zarembski 0:01f31e923fe2 32
Pawel Zarembski 0:01f31e923fe2 33 // Application start must be aligned to page write
Pawel Zarembski 0:01f31e923fe2 34 COMPILER_ASSERT(DAPLINK_ROM_APP_START % DAPLINK_MIN_WRITE_SIZE == 0);
Pawel Zarembski 0:01f31e923fe2 35 // Application size must be a multiple of write size
Pawel Zarembski 0:01f31e923fe2 36 COMPILER_ASSERT(DAPLINK_ROM_APP_SIZE % DAPLINK_MIN_WRITE_SIZE == 0);
Pawel Zarembski 0:01f31e923fe2 37 // Sector size must be a multiple of write size
Pawel Zarembski 0:01f31e923fe2 38 COMPILER_ASSERT(DAPLINK_SECTOR_SIZE % DAPLINK_MIN_WRITE_SIZE == 0);
Pawel Zarembski 0:01f31e923fe2 39 // Application start must be aligned to a sector erase
Pawel Zarembski 0:01f31e923fe2 40 COMPILER_ASSERT(DAPLINK_ROM_APP_START % DAPLINK_SECTOR_SIZE == 0);
Pawel Zarembski 0:01f31e923fe2 41 // Update start must be aligned to sector write
Pawel Zarembski 0:01f31e923fe2 42 COMPILER_ASSERT(DAPLINK_ROM_UPDATE_START % DAPLINK_SECTOR_SIZE == 0);
Pawel Zarembski 0:01f31e923fe2 43 // Update size must be a multiple of sector size
Pawel Zarembski 0:01f31e923fe2 44 COMPILER_ASSERT(DAPLINK_ROM_UPDATE_SIZE % DAPLINK_SECTOR_SIZE == 0);
Pawel Zarembski 0:01f31e923fe2 45
Pawel Zarembski 0:01f31e923fe2 46 typedef enum {
Pawel Zarembski 0:01f31e923fe2 47 STATE_CLOSED,
Pawel Zarembski 0:01f31e923fe2 48 STATE_OPEN,
Pawel Zarembski 0:01f31e923fe2 49 STATE_ERROR
Pawel Zarembski 0:01f31e923fe2 50 } state_t;
Pawel Zarembski 0:01f31e923fe2 51
Pawel Zarembski 0:01f31e923fe2 52 static error_t init(void);
Pawel Zarembski 0:01f31e923fe2 53 static error_t uninit(void);
Pawel Zarembski 0:01f31e923fe2 54 static error_t program_page(uint32_t addr, const uint8_t *buf, uint32_t size);
Pawel Zarembski 0:01f31e923fe2 55 static error_t erase_sector(uint32_t addr);
Pawel Zarembski 0:01f31e923fe2 56 static error_t erase_chip(void);
Pawel Zarembski 0:01f31e923fe2 57 static uint32_t program_page_min_size(uint32_t addr);
Pawel Zarembski 0:01f31e923fe2 58 static uint32_t erase_sector_size(uint32_t addr);
Pawel Zarembski 0:01f31e923fe2 59
Pawel Zarembski 0:01f31e923fe2 60 static bool page_program_allowed(uint32_t addr, uint32_t size);
Pawel Zarembski 0:01f31e923fe2 61 static bool sector_erase_allowed(uint32_t addr);
Pawel Zarembski 0:01f31e923fe2 62 static error_t intercept_page_write(uint32_t addr, const uint8_t *buf, uint32_t size);
Pawel Zarembski 0:01f31e923fe2 63 static error_t intercept_sector_erase(uint32_t addr);
Pawel Zarembski 0:01f31e923fe2 64 static error_t critical_erase_and_program(uint32_t addr, const uint8_t *data, uint32_t size);
Pawel Zarembski 0:01f31e923fe2 65 static uint8_t target_flash_busy(void);
Pawel Zarembski 0:01f31e923fe2 66
Pawel Zarembski 0:01f31e923fe2 67 static const flash_intf_t flash_intf = {
Pawel Zarembski 0:01f31e923fe2 68 init,
Pawel Zarembski 0:01f31e923fe2 69 uninit,
Pawel Zarembski 0:01f31e923fe2 70 program_page,
Pawel Zarembski 0:01f31e923fe2 71 erase_sector,
Pawel Zarembski 0:01f31e923fe2 72 erase_chip,
Pawel Zarembski 0:01f31e923fe2 73 program_page_min_size,
Pawel Zarembski 0:01f31e923fe2 74 erase_sector_size,
Pawel Zarembski 0:01f31e923fe2 75 target_flash_busy,
Pawel Zarembski 0:01f31e923fe2 76 };
Pawel Zarembski 0:01f31e923fe2 77
Pawel Zarembski 0:01f31e923fe2 78 const flash_intf_t *const flash_intf_iap_protected = &flash_intf;
Pawel Zarembski 0:01f31e923fe2 79
Pawel Zarembski 0:01f31e923fe2 80 static state_t state = STATE_CLOSED;
Pawel Zarembski 0:01f31e923fe2 81 static bool update_complete;
Pawel Zarembski 0:01f31e923fe2 82 static bool mass_erase_performed;
Pawel Zarembski 0:01f31e923fe2 83 static bool current_sector_set;
Pawel Zarembski 0:01f31e923fe2 84 static uint32_t current_sector;
Pawel Zarembski 0:01f31e923fe2 85 static uint32_t current_sector_size;
Pawel Zarembski 0:01f31e923fe2 86 static bool current_page_set;
Pawel Zarembski 0:01f31e923fe2 87 static uint32_t current_page;
Pawel Zarembski 0:01f31e923fe2 88 static uint32_t current_page_write_size;
Pawel Zarembski 0:01f31e923fe2 89 static uint32_t crc;
Pawel Zarembski 0:01f31e923fe2 90 static uint8_t sector_buf[DAPLINK_SECTOR_SIZE];
Pawel Zarembski 0:01f31e923fe2 91
Pawel Zarembski 0:01f31e923fe2 92 static error_t init()
Pawel Zarembski 0:01f31e923fe2 93 {
Pawel Zarembski 0:01f31e923fe2 94 int iap_status;
Pawel Zarembski 0:01f31e923fe2 95 bool update_supported = DAPLINK_ROM_UPDATE_SIZE != 0;
Pawel Zarembski 0:01f31e923fe2 96
Pawel Zarembski 0:01f31e923fe2 97 if (state != STATE_CLOSED) {
Pawel Zarembski 0:01f31e923fe2 98 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 99 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 100 }
Pawel Zarembski 0:01f31e923fe2 101
Pawel Zarembski 0:01f31e923fe2 102 if (!update_supported) {
Pawel Zarembski 0:01f31e923fe2 103 return ERROR_IAP_UPDT_NOT_SUPPORTED;
Pawel Zarembski 0:01f31e923fe2 104 }
Pawel Zarembski 0:01f31e923fe2 105
Pawel Zarembski 0:01f31e923fe2 106 iap_status = Init(0, 0, 0);
Pawel Zarembski 0:01f31e923fe2 107
Pawel Zarembski 0:01f31e923fe2 108 if (iap_status != 0) {
Pawel Zarembski 0:01f31e923fe2 109 return ERROR_IAP_INIT;
Pawel Zarembski 0:01f31e923fe2 110 }
Pawel Zarembski 0:01f31e923fe2 111
Pawel Zarembski 0:01f31e923fe2 112 update_complete = false;
Pawel Zarembski 0:01f31e923fe2 113 mass_erase_performed = false;
Pawel Zarembski 0:01f31e923fe2 114 current_sector_set = false;
Pawel Zarembski 0:01f31e923fe2 115 current_sector = 0;
Pawel Zarembski 0:01f31e923fe2 116 current_sector_size = 0;
Pawel Zarembski 0:01f31e923fe2 117 current_page_set = false;
Pawel Zarembski 0:01f31e923fe2 118 current_page = 0;
Pawel Zarembski 0:01f31e923fe2 119 current_page_write_size = 0;
Pawel Zarembski 0:01f31e923fe2 120 crc = 0;
Pawel Zarembski 0:01f31e923fe2 121 memset(sector_buf, 0, sizeof(sector_buf));
Pawel Zarembski 0:01f31e923fe2 122 state = STATE_OPEN;
Pawel Zarembski 0:01f31e923fe2 123 return ERROR_SUCCESS;
Pawel Zarembski 0:01f31e923fe2 124 }
Pawel Zarembski 0:01f31e923fe2 125
Pawel Zarembski 0:01f31e923fe2 126 static error_t uninit(void)
Pawel Zarembski 0:01f31e923fe2 127 {
Pawel Zarembski 0:01f31e923fe2 128 int iap_status;
Pawel Zarembski 0:01f31e923fe2 129
Pawel Zarembski 0:01f31e923fe2 130 if (STATE_CLOSED == state) {
Pawel Zarembski 0:01f31e923fe2 131 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 132 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 133 }
Pawel Zarembski 0:01f31e923fe2 134
Pawel Zarembski 0:01f31e923fe2 135 state = STATE_CLOSED;
Pawel Zarembski 0:01f31e923fe2 136 iap_status = UnInit(0);
Pawel Zarembski 0:01f31e923fe2 137
Pawel Zarembski 0:01f31e923fe2 138 if (iap_status != 0) {
Pawel Zarembski 0:01f31e923fe2 139 return ERROR_IAP_UNINIT;
Pawel Zarembski 0:01f31e923fe2 140 }
Pawel Zarembski 0:01f31e923fe2 141
Pawel Zarembski 0:01f31e923fe2 142 if (!update_complete && !daplink_is_bootloader()) {
Pawel Zarembski 0:01f31e923fe2 143 // Interface - Error if the bootloader update is not complete
Pawel Zarembski 0:01f31e923fe2 144 // Bootloader - For 3rd party applications the end of the update
Pawel Zarembski 0:01f31e923fe2 145 // is unknown so it is not an error if the transfer
Pawel Zarembski 0:01f31e923fe2 146 // ends early.
Pawel Zarembski 0:01f31e923fe2 147 return ERROR_IAP_UPDT_INCOMPLETE;
Pawel Zarembski 0:01f31e923fe2 148 }
Pawel Zarembski 0:01f31e923fe2 149
Pawel Zarembski 0:01f31e923fe2 150 return ERROR_SUCCESS;
Pawel Zarembski 0:01f31e923fe2 151 }
Pawel Zarembski 0:01f31e923fe2 152
Pawel Zarembski 0:01f31e923fe2 153 static error_t program_page(uint32_t addr, const uint8_t *buf, uint32_t size)
Pawel Zarembski 0:01f31e923fe2 154 {
Pawel Zarembski 0:01f31e923fe2 155 uint32_t iap_status;
Pawel Zarembski 0:01f31e923fe2 156 error_t status;
Pawel Zarembski 0:01f31e923fe2 157 uint32_t min_prog_size;
Pawel Zarembski 0:01f31e923fe2 158 uint32_t sector_size;
Pawel Zarembski 0:01f31e923fe2 159 uint32_t updt_end = DAPLINK_ROM_UPDATE_START + DAPLINK_ROM_UPDATE_SIZE;
Pawel Zarembski 0:01f31e923fe2 160
Pawel Zarembski 0:01f31e923fe2 161 if (state != STATE_OPEN) {
Pawel Zarembski 0:01f31e923fe2 162 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 163 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 164 }
Pawel Zarembski 0:01f31e923fe2 165
Pawel Zarembski 0:01f31e923fe2 166 min_prog_size = program_page_min_size(addr);
Pawel Zarembski 0:01f31e923fe2 167 sector_size = erase_sector_size(addr);
Pawel Zarembski 0:01f31e923fe2 168
Pawel Zarembski 0:01f31e923fe2 169 // Address must be on a write size boundary
Pawel Zarembski 0:01f31e923fe2 170 if (addr % min_prog_size != 0) {
Pawel Zarembski 0:01f31e923fe2 171 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 172 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 173 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 174 }
Pawel Zarembski 0:01f31e923fe2 175
Pawel Zarembski 0:01f31e923fe2 176 // Programming size must be a non-zero multiple of the minimum write size
Pawel Zarembski 0:01f31e923fe2 177 if ((size < min_prog_size) || (size % min_prog_size != 0)) {
Pawel Zarembski 0:01f31e923fe2 178 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 179 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 180 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 181 }
Pawel Zarembski 0:01f31e923fe2 182
Pawel Zarembski 0:01f31e923fe2 183 // Write must not cross a sector boundary
Pawel Zarembski 0:01f31e923fe2 184 if ((addr % sector_size) + size > sector_size) {
Pawel Zarembski 0:01f31e923fe2 185 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 186 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 187 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 188 }
Pawel Zarembski 0:01f31e923fe2 189
Pawel Zarembski 0:01f31e923fe2 190 // Write must be in an erased sector (current_sector is always erased if it is set)
Pawel Zarembski 0:01f31e923fe2 191 if (!mass_erase_performed) {
Pawel Zarembski 0:01f31e923fe2 192 if (!current_sector_set) {
Pawel Zarembski 0:01f31e923fe2 193 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 194 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 195 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 196 }
Pawel Zarembski 0:01f31e923fe2 197
Pawel Zarembski 0:01f31e923fe2 198 if ((addr < current_sector) || (addr >= current_sector + current_sector_size)) {
Pawel Zarembski 0:01f31e923fe2 199 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 200 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 201 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 202 }
Pawel Zarembski 0:01f31e923fe2 203 }
Pawel Zarembski 0:01f31e923fe2 204
Pawel Zarembski 0:01f31e923fe2 205 // Address must be sequential - no gaps
Pawel Zarembski 0:01f31e923fe2 206 if (current_page_set && (addr != current_page + current_page_write_size)) {
Pawel Zarembski 0:01f31e923fe2 207 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 208 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 209 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 210 }
Pawel Zarembski 0:01f31e923fe2 211
Pawel Zarembski 0:01f31e923fe2 212 if (!page_program_allowed(addr, size)) {
Pawel Zarembski 0:01f31e923fe2 213 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 214 return ERROR_IAP_WRITE;
Pawel Zarembski 0:01f31e923fe2 215 }
Pawel Zarembski 0:01f31e923fe2 216
Pawel Zarembski 0:01f31e923fe2 217 current_page_set = true;
Pawel Zarembski 0:01f31e923fe2 218 current_page = addr;
Pawel Zarembski 0:01f31e923fe2 219 current_page_write_size = size;
Pawel Zarembski 0:01f31e923fe2 220 status = intercept_page_write(addr, buf, size);
Pawel Zarembski 0:01f31e923fe2 221
Pawel Zarembski 0:01f31e923fe2 222 if (status != ERROR_IAP_NO_INTERCEPT) {
Pawel Zarembski 0:01f31e923fe2 223 // The operation has been intercepted so
Pawel Zarembski 0:01f31e923fe2 224 // return the result
Pawel Zarembski 0:01f31e923fe2 225 if (ERROR_SUCCESS != status) {
Pawel Zarembski 0:01f31e923fe2 226 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 227 }
Pawel Zarembski 0:01f31e923fe2 228
Pawel Zarembski 0:01f31e923fe2 229 return status;
Pawel Zarembski 0:01f31e923fe2 230 }
Pawel Zarembski 0:01f31e923fe2 231
Pawel Zarembski 0:01f31e923fe2 232 iap_status = flash_program_page(addr, size, (uint8_t *)buf);
Pawel Zarembski 0:01f31e923fe2 233
Pawel Zarembski 0:01f31e923fe2 234 if (iap_status != 0) {
Pawel Zarembski 0:01f31e923fe2 235 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 236 return ERROR_IAP_WRITE;
Pawel Zarembski 0:01f31e923fe2 237 }
Pawel Zarembski 0:01f31e923fe2 238
Pawel Zarembski 0:01f31e923fe2 239 if (addr + size >= updt_end) {
Pawel Zarembski 0:01f31e923fe2 240 // Something has been updated so recompute the crc
Pawel Zarembski 0:01f31e923fe2 241 info_crc_compute();
Pawel Zarembski 0:01f31e923fe2 242 update_complete = true;
Pawel Zarembski 0:01f31e923fe2 243 }
Pawel Zarembski 0:01f31e923fe2 244
Pawel Zarembski 0:01f31e923fe2 245 return ERROR_SUCCESS;
Pawel Zarembski 0:01f31e923fe2 246 }
Pawel Zarembski 0:01f31e923fe2 247
Pawel Zarembski 0:01f31e923fe2 248 static error_t erase_sector(uint32_t addr)
Pawel Zarembski 0:01f31e923fe2 249 {
Pawel Zarembski 0:01f31e923fe2 250 uint32_t iap_status;
Pawel Zarembski 0:01f31e923fe2 251 error_t status;
Pawel Zarembski 0:01f31e923fe2 252 uint32_t sector_size;
Pawel Zarembski 0:01f31e923fe2 253
Pawel Zarembski 0:01f31e923fe2 254 if (state != STATE_OPEN) {
Pawel Zarembski 0:01f31e923fe2 255 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 256 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 257 }
Pawel Zarembski 0:01f31e923fe2 258
Pawel Zarembski 0:01f31e923fe2 259 // Address must be on a sector boundary
Pawel Zarembski 0:01f31e923fe2 260 sector_size = erase_sector_size(addr);
Pawel Zarembski 0:01f31e923fe2 261
Pawel Zarembski 0:01f31e923fe2 262 if (addr % sector_size != 0) {
Pawel Zarembski 0:01f31e923fe2 263 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 264 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 265 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 266 }
Pawel Zarembski 0:01f31e923fe2 267
Pawel Zarembski 0:01f31e923fe2 268 // Address must be sequential - no gaps
Pawel Zarembski 0:01f31e923fe2 269 if (current_sector_set && (addr != current_sector + current_sector_size)) {
Pawel Zarembski 0:01f31e923fe2 270 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 271 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 272 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 273 }
Pawel Zarembski 0:01f31e923fe2 274
Pawel Zarembski 0:01f31e923fe2 275 if (!sector_erase_allowed(addr)) {
Pawel Zarembski 0:01f31e923fe2 276 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 277 return ERROR_IAP_ERASE_SECTOR;
Pawel Zarembski 0:01f31e923fe2 278 }
Pawel Zarembski 0:01f31e923fe2 279
Pawel Zarembski 0:01f31e923fe2 280 current_sector_set = true;
Pawel Zarembski 0:01f31e923fe2 281 current_sector = addr;
Pawel Zarembski 0:01f31e923fe2 282 current_sector_size = sector_size;
Pawel Zarembski 0:01f31e923fe2 283 status = intercept_sector_erase(addr);
Pawel Zarembski 0:01f31e923fe2 284
Pawel Zarembski 0:01f31e923fe2 285 if (status != ERROR_IAP_NO_INTERCEPT) {
Pawel Zarembski 0:01f31e923fe2 286 // The operation has been intercepted so
Pawel Zarembski 0:01f31e923fe2 287 // return the result
Pawel Zarembski 0:01f31e923fe2 288 if (ERROR_SUCCESS != status) {
Pawel Zarembski 0:01f31e923fe2 289 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 290 }
Pawel Zarembski 0:01f31e923fe2 291
Pawel Zarembski 0:01f31e923fe2 292 return status;
Pawel Zarembski 0:01f31e923fe2 293 }
Pawel Zarembski 0:01f31e923fe2 294
Pawel Zarembski 0:01f31e923fe2 295 iap_status = flash_erase_sector(addr);
Pawel Zarembski 0:01f31e923fe2 296
Pawel Zarembski 0:01f31e923fe2 297 if (iap_status != 0) {
Pawel Zarembski 0:01f31e923fe2 298 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 299 return ERROR_IAP_ERASE_SECTOR;
Pawel Zarembski 0:01f31e923fe2 300 }
Pawel Zarembski 0:01f31e923fe2 301
Pawel Zarembski 0:01f31e923fe2 302 return ERROR_SUCCESS;
Pawel Zarembski 0:01f31e923fe2 303 }
Pawel Zarembski 0:01f31e923fe2 304
Pawel Zarembski 0:01f31e923fe2 305 static error_t erase_chip(void)
Pawel Zarembski 0:01f31e923fe2 306 {
Pawel Zarembski 0:01f31e923fe2 307 uint32_t updt_start = DAPLINK_ROM_UPDATE_START;
Pawel Zarembski 0:01f31e923fe2 308 uint32_t updt_end = DAPLINK_ROM_UPDATE_START + DAPLINK_ROM_UPDATE_SIZE;
Pawel Zarembski 0:01f31e923fe2 309
Pawel Zarembski 0:01f31e923fe2 310 if (state != STATE_OPEN) {
Pawel Zarembski 0:01f31e923fe2 311 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 312 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 313 }
Pawel Zarembski 0:01f31e923fe2 314
Pawel Zarembski 0:01f31e923fe2 315 if (mass_erase_performed) {
Pawel Zarembski 0:01f31e923fe2 316 // Mass erase only allowed once
Pawel Zarembski 0:01f31e923fe2 317 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 318 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 319 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 320 }
Pawel Zarembski 0:01f31e923fe2 321
Pawel Zarembski 0:01f31e923fe2 322 for (uint32_t addr = updt_start; addr < updt_end; addr += DAPLINK_SECTOR_SIZE) {
Pawel Zarembski 0:01f31e923fe2 323 error_t status;
Pawel Zarembski 0:01f31e923fe2 324 status = erase_sector(addr);
Pawel Zarembski 0:01f31e923fe2 325
Pawel Zarembski 0:01f31e923fe2 326 if (status != ERROR_SUCCESS) {
Pawel Zarembski 0:01f31e923fe2 327 state = STATE_ERROR;
Pawel Zarembski 0:01f31e923fe2 328 return ERROR_IAP_ERASE_ALL;
Pawel Zarembski 0:01f31e923fe2 329 }
Pawel Zarembski 0:01f31e923fe2 330 }
Pawel Zarembski 0:01f31e923fe2 331
Pawel Zarembski 0:01f31e923fe2 332 mass_erase_performed = true;
Pawel Zarembski 0:01f31e923fe2 333 return ERROR_SUCCESS;
Pawel Zarembski 0:01f31e923fe2 334 }
Pawel Zarembski 0:01f31e923fe2 335
Pawel Zarembski 0:01f31e923fe2 336 static uint32_t program_page_min_size(uint32_t addr)
Pawel Zarembski 0:01f31e923fe2 337 {
Pawel Zarembski 0:01f31e923fe2 338 return DAPLINK_MIN_WRITE_SIZE;
Pawel Zarembski 0:01f31e923fe2 339 }
Pawel Zarembski 0:01f31e923fe2 340
Pawel Zarembski 0:01f31e923fe2 341 static uint32_t erase_sector_size(uint32_t addr)
Pawel Zarembski 0:01f31e923fe2 342 {
Pawel Zarembski 0:01f31e923fe2 343 return DAPLINK_SECTOR_SIZE;
Pawel Zarembski 0:01f31e923fe2 344 }
Pawel Zarembski 0:01f31e923fe2 345
Pawel Zarembski 0:01f31e923fe2 346 static bool page_program_allowed(uint32_t addr, uint32_t size)
Pawel Zarembski 0:01f31e923fe2 347 {
Pawel Zarembski 0:01f31e923fe2 348 // Check if any data would overlap with the application region
Pawel Zarembski 0:01f31e923fe2 349 if ((addr < DAPLINK_ROM_APP_START + DAPLINK_ROM_APP_SIZE) && (addr + size > DAPLINK_ROM_APP_START)) {
Pawel Zarembski 0:01f31e923fe2 350 return false;
Pawel Zarembski 0:01f31e923fe2 351 }
Pawel Zarembski 0:01f31e923fe2 352
Pawel Zarembski 0:01f31e923fe2 353 return true;
Pawel Zarembski 0:01f31e923fe2 354 }
Pawel Zarembski 0:01f31e923fe2 355
Pawel Zarembski 0:01f31e923fe2 356 static bool sector_erase_allowed(uint32_t addr)
Pawel Zarembski 0:01f31e923fe2 357 {
Pawel Zarembski 0:01f31e923fe2 358 uint32_t app_start = DAPLINK_ROM_APP_START;
Pawel Zarembski 0:01f31e923fe2 359 uint32_t app_end = DAPLINK_ROM_APP_START + DAPLINK_ROM_APP_SIZE;
Pawel Zarembski 0:01f31e923fe2 360
Pawel Zarembski 0:01f31e923fe2 361 // Check if the sector is part of the application
Pawel Zarembski 0:01f31e923fe2 362 if ((addr >= app_start) && (addr < app_end)) {
Pawel Zarembski 0:01f31e923fe2 363 return false;
Pawel Zarembski 0:01f31e923fe2 364 }
Pawel Zarembski 0:01f31e923fe2 365
Pawel Zarembski 0:01f31e923fe2 366 return true;
Pawel Zarembski 0:01f31e923fe2 367 }
Pawel Zarembski 0:01f31e923fe2 368
Pawel Zarembski 0:01f31e923fe2 369 static error_t intercept_page_write(uint32_t addr, const uint8_t *buf, uint32_t size)
Pawel Zarembski 0:01f31e923fe2 370 {
Pawel Zarembski 0:01f31e923fe2 371 error_t status;
Pawel Zarembski 0:01f31e923fe2 372 uint32_t crc_size;
Pawel Zarembski 0:01f31e923fe2 373 uint32_t updt_start = DAPLINK_ROM_UPDATE_START;
Pawel Zarembski 0:01f31e923fe2 374 uint32_t updt_end = DAPLINK_ROM_UPDATE_START + DAPLINK_ROM_UPDATE_SIZE;
Pawel Zarembski 0:01f31e923fe2 375
Pawel Zarembski 0:01f31e923fe2 376 if (state != STATE_OPEN) {
Pawel Zarembski 0:01f31e923fe2 377 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 378 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 379 }
Pawel Zarembski 0:01f31e923fe2 380
Pawel Zarembski 0:01f31e923fe2 381 if ((addr < updt_start) || (addr >= updt_end)) {
Pawel Zarembski 0:01f31e923fe2 382 return ERROR_IAP_OUT_OF_BOUNDS;
Pawel Zarembski 0:01f31e923fe2 383 }
Pawel Zarembski 0:01f31e923fe2 384
Pawel Zarembski 0:01f31e923fe2 385 if (!daplink_is_interface()) {
Pawel Zarembski 0:01f31e923fe2 386 return ERROR_IAP_NO_INTERCEPT;
Pawel Zarembski 0:01f31e923fe2 387 }
Pawel Zarembski 0:01f31e923fe2 388
Pawel Zarembski 0:01f31e923fe2 389 /* Everything below here is interface specific */
Pawel Zarembski 0:01f31e923fe2 390 crc_size = MIN(size, updt_end - addr - 4);
Pawel Zarembski 0:01f31e923fe2 391 crc = crc32_continue(crc, buf, crc_size);
Pawel Zarembski 0:01f31e923fe2 392
Pawel Zarembski 0:01f31e923fe2 393 // Intercept the data if it is in the first sector
Pawel Zarembski 0:01f31e923fe2 394 if ((addr >= updt_start) && (addr < updt_start + DAPLINK_SECTOR_SIZE)) {
Pawel Zarembski 0:01f31e923fe2 395 uint32_t buf_offset = addr - updt_start;
Pawel Zarembski 0:01f31e923fe2 396 memcpy(sector_buf + buf_offset, buf, size);
Pawel Zarembski 0:01f31e923fe2 397 // Intercept was successful
Pawel Zarembski 0:01f31e923fe2 398 return ERROR_SUCCESS;
Pawel Zarembski 0:01f31e923fe2 399 }
Pawel Zarembski 0:01f31e923fe2 400
Pawel Zarembski 0:01f31e923fe2 401 // Finalize update if this is the last sector
Pawel Zarembski 0:01f31e923fe2 402 if (updt_end == addr + size) {
Pawel Zarembski 0:01f31e923fe2 403 uint32_t iap_status;
Pawel Zarembski 0:01f31e923fe2 404 uint32_t size_left = updt_end - addr;
Pawel Zarembski 0:01f31e923fe2 405 uint32_t crc_in_image = (buf[size_left - 4] << 0) |
Pawel Zarembski 0:01f31e923fe2 406 (buf[size_left - 3] << 8) |
Pawel Zarembski 0:01f31e923fe2 407 (buf[size_left - 2] << 16) |
Pawel Zarembski 0:01f31e923fe2 408 (buf[size_left - 1] << 24);
Pawel Zarembski 0:01f31e923fe2 409
Pawel Zarembski 0:01f31e923fe2 410 if (crc != crc_in_image) {
Pawel Zarembski 0:01f31e923fe2 411 return ERROR_BL_UPDT_BAD_CRC;
Pawel Zarembski 0:01f31e923fe2 412 }
Pawel Zarembski 0:01f31e923fe2 413
Pawel Zarembski 0:01f31e923fe2 414 // Program the current buffer
Pawel Zarembski 0:01f31e923fe2 415 iap_status = flash_program_page(addr, size, (uint8_t *)buf);
Pawel Zarembski 0:01f31e923fe2 416
Pawel Zarembski 0:01f31e923fe2 417 if (iap_status != 0) {
Pawel Zarembski 0:01f31e923fe2 418 return ERROR_IAP_WRITE;
Pawel Zarembski 0:01f31e923fe2 419 }
Pawel Zarembski 0:01f31e923fe2 420
Pawel Zarembski 0:01f31e923fe2 421 status = critical_erase_and_program(DAPLINK_ROM_UPDATE_START, sector_buf, DAPLINK_SECTOR_SIZE);
Pawel Zarembski 0:01f31e923fe2 422
Pawel Zarembski 0:01f31e923fe2 423 if (ERROR_SUCCESS == status) {
Pawel Zarembski 0:01f31e923fe2 424 status = ERROR_SUCCESS;
Pawel Zarembski 0:01f31e923fe2 425 }
Pawel Zarembski 0:01f31e923fe2 426
Pawel Zarembski 0:01f31e923fe2 427 // The bootloader has been updated so recompute the crc
Pawel Zarembski 0:01f31e923fe2 428 info_crc_compute();
Pawel Zarembski 0:01f31e923fe2 429 update_complete = true;
Pawel Zarembski 0:01f31e923fe2 430 return status;
Pawel Zarembski 0:01f31e923fe2 431 }
Pawel Zarembski 0:01f31e923fe2 432
Pawel Zarembski 0:01f31e923fe2 433 return ERROR_IAP_NO_INTERCEPT;
Pawel Zarembski 0:01f31e923fe2 434 }
Pawel Zarembski 0:01f31e923fe2 435
Pawel Zarembski 0:01f31e923fe2 436 static error_t intercept_sector_erase(uint32_t addr)
Pawel Zarembski 0:01f31e923fe2 437 {
Pawel Zarembski 0:01f31e923fe2 438 error_t status;
Pawel Zarembski 0:01f31e923fe2 439 uint32_t updt_start = DAPLINK_ROM_UPDATE_START;
Pawel Zarembski 0:01f31e923fe2 440 uint32_t updt_end = DAPLINK_ROM_UPDATE_START + DAPLINK_ROM_UPDATE_SIZE;
Pawel Zarembski 0:01f31e923fe2 441
Pawel Zarembski 0:01f31e923fe2 442 if (state != STATE_OPEN) {
Pawel Zarembski 0:01f31e923fe2 443 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 444 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 445 }
Pawel Zarembski 0:01f31e923fe2 446
Pawel Zarembski 0:01f31e923fe2 447 if ((addr < updt_start) || (addr >= updt_end)) {
Pawel Zarembski 0:01f31e923fe2 448 return ERROR_IAP_OUT_OF_BOUNDS;
Pawel Zarembski 0:01f31e923fe2 449 }
Pawel Zarembski 0:01f31e923fe2 450
Pawel Zarembski 0:01f31e923fe2 451 if (!daplink_is_interface()) {
Pawel Zarembski 0:01f31e923fe2 452 return ERROR_IAP_NO_INTERCEPT;
Pawel Zarembski 0:01f31e923fe2 453 }
Pawel Zarembski 0:01f31e923fe2 454
Pawel Zarembski 0:01f31e923fe2 455 /* Everything below here is interface specific */
Pawel Zarembski 0:01f31e923fe2 456
Pawel Zarembski 0:01f31e923fe2 457 if (DAPLINK_ROM_UPDATE_START == addr) {
Pawel Zarembski 0:01f31e923fe2 458 uint32_t addr = DAPLINK_ROM_UPDATE_START;
Pawel Zarembski 0:01f31e923fe2 459 status = critical_erase_and_program(addr, (uint8_t *)DAPLINK_ROM_IF_START, DAPLINK_MIN_WRITE_SIZE);
Pawel Zarembski 0:01f31e923fe2 460
Pawel Zarembski 0:01f31e923fe2 461 if (ERROR_SUCCESS == status) {
Pawel Zarembski 0:01f31e923fe2 462 // Intercept was successful
Pawel Zarembski 0:01f31e923fe2 463 status = ERROR_SUCCESS;
Pawel Zarembski 0:01f31e923fe2 464 }
Pawel Zarembski 0:01f31e923fe2 465
Pawel Zarembski 0:01f31e923fe2 466 return status;
Pawel Zarembski 0:01f31e923fe2 467 }
Pawel Zarembski 0:01f31e923fe2 468
Pawel Zarembski 0:01f31e923fe2 469 return ERROR_IAP_NO_INTERCEPT;
Pawel Zarembski 0:01f31e923fe2 470 }
Pawel Zarembski 0:01f31e923fe2 471
Pawel Zarembski 0:01f31e923fe2 472 static error_t critical_erase_and_program(uint32_t addr, const uint8_t *data, uint32_t size)
Pawel Zarembski 0:01f31e923fe2 473 {
Pawel Zarembski 0:01f31e923fe2 474 uint32_t iap_status;
Pawel Zarembski 0:01f31e923fe2 475
Pawel Zarembski 0:01f31e923fe2 476 if (size < DAPLINK_MIN_WRITE_SIZE) {
Pawel Zarembski 0:01f31e923fe2 477 util_assert(0);
Pawel Zarembski 0:01f31e923fe2 478 return ERROR_INTERNAL;
Pawel Zarembski 0:01f31e923fe2 479 }
Pawel Zarembski 0:01f31e923fe2 480
Pawel Zarembski 0:01f31e923fe2 481 // CRITICAL SECTION BELOW HERE!
Pawel Zarembski 0:01f31e923fe2 482 // If something goes wrong with either
Pawel Zarembski 0:01f31e923fe2 483 // the erase or write then the device
Pawel Zarembski 0:01f31e923fe2 484 // will no longer be bootable.
Pawel Zarembski 0:01f31e923fe2 485 // Erase the first sector
Pawel Zarembski 0:01f31e923fe2 486 iap_status = flash_erase_sector(addr);
Pawel Zarembski 0:01f31e923fe2 487
Pawel Zarembski 0:01f31e923fe2 488 if (iap_status != 0) {
Pawel Zarembski 0:01f31e923fe2 489 return ERROR_ERASE_ALL;
Pawel Zarembski 0:01f31e923fe2 490 }
Pawel Zarembski 0:01f31e923fe2 491
Pawel Zarembski 0:01f31e923fe2 492 // Program the interface's vector table
Pawel Zarembski 0:01f31e923fe2 493 iap_status = flash_program_page(addr, size, (uint8_t *)data);
Pawel Zarembski 0:01f31e923fe2 494
Pawel Zarembski 0:01f31e923fe2 495 if (iap_status != 0) {
Pawel Zarembski 0:01f31e923fe2 496 return ERROR_IAP_WRITE;
Pawel Zarembski 0:01f31e923fe2 497 }
Pawel Zarembski 0:01f31e923fe2 498
Pawel Zarembski 0:01f31e923fe2 499 return ERROR_SUCCESS;
Pawel Zarembski 0:01f31e923fe2 500 }
Pawel Zarembski 0:01f31e923fe2 501
Pawel Zarembski 0:01f31e923fe2 502 static uint8_t target_flash_busy(void){
Pawel Zarembski 0:01f31e923fe2 503 return (state == STATE_OPEN);
Pawel Zarembski 0:01f31e923fe2 504 }