You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

433 lines
12 KiB

  1. /***************************************************************************
  2. * Copyright (C) 2020 Loci Controls Inc *
  3. * Copyright (C) 2017 by Texas Instruments, Inc. *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; either version 2 of the License, or *
  8. * (at your option) any later version. *
  9. * *
  10. * This program is distributed in the hope that it will be useful, *
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  13. * GNU General Public License for more details. *
  14. * *
  15. * You should have received a copy of the GNU General Public License *
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  17. ***************************************************************************/
  18. #ifdef HAVE_CONFIG_H
  19. #include "config.h"
  20. #endif
  21. #include "imp.h"
  22. #include "cc2538.h"
  23. #include <helper/binarybuffer.h>
  24. #include <helper/time_support.h>
  25. #include <target/algorithm.h>
  26. #include <target/armv7m.h>
  27. #include <target/image.h>
  28. #define FLASH_TIMEOUT 10000
  29. struct cc2538_bank {
  30. const char *family_name;
  31. uint16_t chip_id;
  32. bool probed;
  33. struct working_area *working_area;
  34. struct armv7m_algorithm armv7m_info;
  35. const uint8_t *algo_code;
  36. uint32_t algo_size;
  37. uint32_t algo_working_size;
  38. uint32_t buffer_addr[2];
  39. uint32_t params_addr[2];
  40. };
  41. static int cc2538_auto_probe(struct flash_bank *bank);
  42. static int cc2538_wait_algo_done(struct flash_bank *bank, uint32_t params_addr)
  43. {
  44. struct target *target = bank->target;
  45. uint32_t status_addr = params_addr + CC2538_STATUS_OFFSET;
  46. uint32_t status = CC2538_BUFFER_FULL;
  47. long long start_ms;
  48. long long elapsed_ms;
  49. int retval = ERROR_OK;
  50. start_ms = timeval_ms();
  51. while (CC2538_BUFFER_FULL == status) {
  52. retval = target_read_u32(target, status_addr, &status);
  53. if (ERROR_OK != retval)
  54. return retval;
  55. elapsed_ms = timeval_ms() - start_ms;
  56. if (elapsed_ms > 500)
  57. keep_alive();
  58. if (elapsed_ms > FLASH_TIMEOUT)
  59. break;
  60. };
  61. if (CC2538_BUFFER_EMPTY != status) {
  62. LOG_ERROR("cc2538: Flash operation failed (0x%08x)", status);
  63. return ERROR_FAIL;
  64. }
  65. return ERROR_OK;
  66. }
  67. static int cc2538_init(struct flash_bank *bank)
  68. {
  69. struct target *target = bank->target;
  70. struct cc2538_bank *cc2538_bank = bank->driver_priv;
  71. int retval;
  72. /* Make sure we've probed the flash to get the size */
  73. retval = cc2538_auto_probe(bank);
  74. if (ERROR_OK != retval)
  75. return retval;
  76. /* Check for working area to use for flash helper algorithm */
  77. if (NULL != cc2538_bank->working_area)
  78. target_free_working_area(target, cc2538_bank->working_area);
  79. retval = target_alloc_working_area(target, cc2538_bank->algo_working_size,
  80. &cc2538_bank->working_area);
  81. if (ERROR_OK != retval)
  82. return retval;
  83. /* Confirm the defined working address is the area we need to use */
  84. if (CC2538_ALGO_BASE_ADDRESS != cc2538_bank->working_area->address)
  85. return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
  86. /* Write flash helper algorithm into target memory */
  87. retval = target_write_buffer(target, CC2538_ALGO_BASE_ADDRESS,
  88. cc2538_bank->algo_size, cc2538_bank->algo_code);
  89. if (ERROR_OK != retval) {
  90. LOG_ERROR("cc2538: Failed to load flash helper algorithm");
  91. target_free_working_area(target, cc2538_bank->working_area);
  92. return retval;
  93. }
  94. /* Initialize the ARMv7 specific info to run the algorithm */
  95. cc2538_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
  96. cc2538_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
  97. /* Begin executing the flash helper algorithm */
  98. retval = target_start_algorithm(target, 0, NULL, 0, NULL,
  99. CC2538_ALGO_BASE_ADDRESS, 0, &cc2538_bank->armv7m_info);
  100. if (ERROR_OK != retval) {
  101. LOG_ERROR("cc2538: Failed to start flash helper algorithm");
  102. target_free_working_area(target, cc2538_bank->working_area);
  103. return retval;
  104. }
  105. /*
  106. * At this point, the algorithm is running on the target and
  107. * ready to receive commands and data to flash the target
  108. */
  109. return retval;
  110. }
  111. static int cc2538_quit(struct flash_bank *bank)
  112. {
  113. struct target *target = bank->target;
  114. struct cc2538_bank *cc2538_bank = bank->driver_priv;
  115. int retval;
  116. /* Regardless of the algo's status, attempt to halt the target */
  117. (void)target_halt(target);
  118. /* Now confirm target halted and clean up from flash helper algorithm */
  119. retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, FLASH_TIMEOUT,
  120. &cc2538_bank->armv7m_info);
  121. target_free_working_area(target, cc2538_bank->working_area);
  122. cc2538_bank->working_area = NULL;
  123. return retval;
  124. }
  125. static int cc2538_mass_erase(struct flash_bank *bank)
  126. {
  127. struct target *target = bank->target;
  128. struct cc2538_bank *cc2538_bank = bank->driver_priv;
  129. struct cc2538_algo_params algo_params;
  130. int retval;
  131. if (TARGET_HALTED != target->state) {
  132. LOG_ERROR("Target not halted");
  133. return ERROR_TARGET_NOT_HALTED;
  134. }
  135. retval = cc2538_init(bank);
  136. if (ERROR_OK != retval)
  137. return retval;
  138. /* Initialize algorithm parameters */
  139. buf_set_u32(algo_params.address, 0, 32, 0);
  140. buf_set_u32(algo_params.length, 0, 32, 4);
  141. buf_set_u32(algo_params.command, 0, 32, CC2538_CMD_ERASE_ALL);
  142. buf_set_u32(algo_params.status, 0, 32, CC2538_BUFFER_FULL);
  143. /* Issue flash helper algorithm parameters for mass erase */
  144. retval = target_write_buffer(target, cc2538_bank->params_addr[0],
  145. sizeof(algo_params), (uint8_t *)&algo_params);
  146. /* Wait for command to complete */
  147. if (ERROR_OK == retval)
  148. retval = cc2538_wait_algo_done(bank, cc2538_bank->params_addr[0]);
  149. /* Regardless of errors, try to close down algo */
  150. (void)cc2538_quit(bank);
  151. return retval;
  152. }
  153. FLASH_BANK_COMMAND_HANDLER(cc2538_flash_bank_command)
  154. {
  155. struct cc2538_bank *cc2538_bank;
  156. if (CMD_ARGC < 6)
  157. return ERROR_COMMAND_SYNTAX_ERROR;
  158. cc2538_bank = malloc(sizeof(struct cc2538_bank));
  159. if (NULL == cc2538_bank)
  160. return ERROR_FAIL;
  161. /* Initialize private flash information */
  162. memset((void *)cc2538_bank, 0x00, sizeof(struct cc2538_bank));
  163. /* Finish initialization of bank */
  164. bank->driver_priv = cc2538_bank;
  165. bank->next = NULL;
  166. return ERROR_OK;
  167. }
  168. static int cc2538_erase(struct flash_bank *bank,
  169. unsigned int first, unsigned int last)
  170. {
  171. struct target *target = bank->target;
  172. struct cc2538_bank *cc2538_bank = bank->driver_priv;
  173. struct cc2538_algo_params algo_params;
  174. uint32_t address;
  175. uint32_t length;
  176. int retval;
  177. if (TARGET_HALTED != target->state) {
  178. LOG_ERROR("Target not halted");
  179. return ERROR_TARGET_NOT_HALTED;
  180. }
  181. /* Do a mass erase if user requested all sectors of flash */
  182. if ((first == 0) && (last == (bank->num_sectors - 1))) {
  183. /* Request mass erase of flash */
  184. return cc2538_mass_erase(bank);
  185. }
  186. address = bank->base + first * CC2538_SECTOR_LENGTH;
  187. length = (last - first + 1) * CC2538_SECTOR_LENGTH;
  188. retval = cc2538_init(bank);
  189. if (ERROR_OK != retval)
  190. return retval;
  191. /* Set up algorithm parameters for erase command */
  192. buf_set_u32(algo_params.address, 0, 32, address);
  193. buf_set_u32(algo_params.length, 0, 32, length);
  194. buf_set_u32(algo_params.command, 0, 32, CC2538_CMD_ERASE_SECTORS);
  195. buf_set_u32(algo_params.status, 0, 32, CC2538_BUFFER_FULL);
  196. /* Issue flash helper algorithm parameters for erase */
  197. retval = target_write_buffer(target, cc2538_bank->params_addr[0],
  198. sizeof(algo_params), (uint8_t *)&algo_params);
  199. /* If no error, wait for erase to finish */
  200. if (ERROR_OK == retval)
  201. retval = cc2538_wait_algo_done(bank, cc2538_bank->params_addr[0]);
  202. /* Regardless of errors, try to close down algo */
  203. (void)cc2538_quit(bank);
  204. return retval;
  205. }
  206. static int cc2538_write(struct flash_bank *bank, const uint8_t *buffer,
  207. uint32_t offset, uint32_t count)
  208. {
  209. struct target *target = bank->target;
  210. struct cc2538_bank *cc2538_bank = bank->driver_priv;
  211. struct cc2538_algo_params algo_params[2];
  212. uint32_t size = 0;
  213. long long start_ms;
  214. long long elapsed_ms;
  215. uint32_t address;
  216. uint32_t index;
  217. int retval;
  218. if (TARGET_HALTED != target->state) {
  219. LOG_ERROR("Target not halted");
  220. return ERROR_TARGET_NOT_HALTED;
  221. }
  222. retval = cc2538_init(bank);
  223. if (ERROR_OK != retval)
  224. return retval;
  225. /* Initialize algorithm parameters to default values */
  226. buf_set_u32(algo_params[0].command, 0, 32, CC2538_CMD_PROGRAM);
  227. buf_set_u32(algo_params[1].command, 0, 32, CC2538_CMD_PROGRAM);
  228. /* Write requested data, ping-ponging between two buffers */
  229. index = 0;
  230. start_ms = timeval_ms();
  231. address = bank->base + offset;
  232. while (count > 0) {
  233. if (count > CC2538_SECTOR_LENGTH)
  234. size = CC2538_SECTOR_LENGTH;
  235. else
  236. size = count;
  237. /* Put next block of data to flash into buffer */
  238. retval = target_write_buffer(target, cc2538_bank->buffer_addr[index],
  239. size, buffer);
  240. if (ERROR_OK != retval) {
  241. LOG_ERROR("Unable to write data to target memory");
  242. break;
  243. }
  244. /* Update algo parameters for next block */
  245. buf_set_u32(algo_params[index].address, 0, 32, address);
  246. buf_set_u32(algo_params[index].length, 0, 32, size);
  247. buf_set_u32(algo_params[index].status, 0, 32, CC2538_BUFFER_FULL);
  248. /* Issue flash helper algorithm parameters for block write */
  249. retval = target_write_buffer(target, cc2538_bank->params_addr[index],
  250. sizeof(algo_params[index]), (uint8_t *)&algo_params[index]);
  251. if (ERROR_OK != retval)
  252. break;
  253. /* Wait for next ping pong buffer to be ready */
  254. index ^= 1;
  255. retval = cc2538_wait_algo_done(bank, cc2538_bank->params_addr[index]);
  256. if (ERROR_OK != retval)
  257. break;
  258. count -= size;
  259. buffer += size;
  260. address += size;
  261. elapsed_ms = timeval_ms() - start_ms;
  262. if (elapsed_ms > 500)
  263. keep_alive();
  264. }
  265. /* If no error yet, wait for last buffer to finish */
  266. if (ERROR_OK == retval) {
  267. index ^= 1;
  268. retval = cc2538_wait_algo_done(bank, cc2538_bank->params_addr[index]);
  269. }
  270. /* Regardless of errors, try to close down algo */
  271. (void)cc2538_quit(bank);
  272. return retval;
  273. }
  274. static int cc2538_probe(struct flash_bank *bank)
  275. {
  276. struct target *target = bank->target;
  277. struct cc2538_bank *cc2538_bank = bank->driver_priv;
  278. uint32_t value;
  279. int num_sectors;
  280. int retval;
  281. retval = target_read_u32(target, CC2538_FLASH_CTRL_DIECFG0, &value);
  282. if (ERROR_OK != retval)
  283. return retval;
  284. cc2538_bank->chip_id = value >> 16;
  285. num_sectors = ((value & 0x70) >> 4) * 0x20000 / CC2538_SECTOR_LENGTH;
  286. if (num_sectors > CC2538_MAX_SECTORS)
  287. num_sectors = CC2538_MAX_SECTORS;
  288. bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
  289. if (NULL == bank->sectors)
  290. return ERROR_FAIL;
  291. /* Set up flash helper algorithm */
  292. cc2538_bank->algo_code = cc2538_algo;
  293. cc2538_bank->algo_size = sizeof(cc2538_algo);
  294. cc2538_bank->algo_working_size = CC2538_WORKING_SIZE;
  295. cc2538_bank->buffer_addr[0] = CC2538_ALGO_BUFFER_0;
  296. cc2538_bank->buffer_addr[1] = CC2538_ALGO_BUFFER_1;
  297. cc2538_bank->params_addr[0] = CC2538_ALGO_PARAMS_0;
  298. cc2538_bank->params_addr[1] = CC2538_ALGO_PARAMS_1;
  299. bank->base = CC2538_FLASH_BASE_ADDR;
  300. bank->num_sectors = num_sectors;
  301. bank->size = num_sectors * CC2538_SECTOR_LENGTH;
  302. bank->write_start_alignment = 0;
  303. bank->write_end_alignment = 0;
  304. for (int i = 0; i < num_sectors; i++) {
  305. bank->sectors[i].offset = i * CC2538_SECTOR_LENGTH;
  306. bank->sectors[i].size = CC2538_SECTOR_LENGTH;
  307. bank->sectors[i].is_erased = -1;
  308. bank->sectors[i].is_protected = 0;
  309. }
  310. /* We've successfully determined the stats on the flash bank */
  311. cc2538_bank->probed = true;
  312. /* If we fall through to here, then all went well */
  313. return ERROR_OK;
  314. }
  315. static int cc2538_auto_probe(struct flash_bank *bank)
  316. {
  317. struct cc2538_bank *cc2538_bank = bank->driver_priv;
  318. int retval = ERROR_OK;
  319. if (!cc2538_bank->probed)
  320. retval = cc2538_probe(bank);
  321. return retval;
  322. }
  323. static int cc2538_info(struct flash_bank *bank, struct command_invocation *cmd)
  324. {
  325. struct cc2538_bank *cc2538_bank = bank->driver_priv;
  326. command_print_sameline(cmd,
  327. "cc2538 device: chip ID 0x%04x\n", cc2538_bank->chip_id);
  328. return ERROR_OK;
  329. }
  330. const struct flash_driver cc2538_flash = {
  331. .name = "cc2538",
  332. .flash_bank_command = cc2538_flash_bank_command,
  333. .erase = cc2538_erase,
  334. .write = cc2538_write,
  335. .read = default_flash_read,
  336. .probe = cc2538_probe,
  337. .auto_probe = cc2538_auto_probe,
  338. .erase_check = default_flash_blank_check,
  339. .info = cc2538_info,
  340. .free_driver_priv = default_flash_free_driver_priv,
  341. };