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.
 
 
 
 
 
 

436 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, int first, int last)
  169. {
  170. struct target *target = bank->target;
  171. struct cc2538_bank *cc2538_bank = bank->driver_priv;
  172. struct cc2538_algo_params algo_params;
  173. uint32_t address;
  174. uint32_t length;
  175. int retval;
  176. if (TARGET_HALTED != target->state) {
  177. LOG_ERROR("Target not halted");
  178. return ERROR_TARGET_NOT_HALTED;
  179. }
  180. /* Do a mass erase if user requested all sectors of flash */
  181. if ((first == 0) && (last == (bank->num_sectors - 1))) {
  182. /* Request mass erase of flash */
  183. return cc2538_mass_erase(bank);
  184. }
  185. address = bank->base + first * CC2538_SECTOR_LENGTH;
  186. length = (last - first + 1) * CC2538_SECTOR_LENGTH;
  187. retval = cc2538_init(bank);
  188. if (ERROR_OK != retval)
  189. return retval;
  190. /* Set up algorithm parameters for erase command */
  191. buf_set_u32(algo_params.address, 0, 32, address);
  192. buf_set_u32(algo_params.length, 0, 32, length);
  193. buf_set_u32(algo_params.command, 0, 32, CC2538_CMD_ERASE_SECTORS);
  194. buf_set_u32(algo_params.status, 0, 32, CC2538_BUFFER_FULL);
  195. /* Issue flash helper algorithm parameters for erase */
  196. retval = target_write_buffer(target, cc2538_bank->params_addr[0],
  197. sizeof(algo_params), (uint8_t *)&algo_params);
  198. /* If no error, wait for erase to finish */
  199. if (ERROR_OK == retval)
  200. retval = cc2538_wait_algo_done(bank, cc2538_bank->params_addr[0]);
  201. /* Regardless of errors, try to close down algo */
  202. (void)cc2538_quit(bank);
  203. return retval;
  204. }
  205. static int cc2538_write(struct flash_bank *bank, const uint8_t *buffer,
  206. uint32_t offset, uint32_t count)
  207. {
  208. struct target *target = bank->target;
  209. struct cc2538_bank *cc2538_bank = bank->driver_priv;
  210. struct cc2538_algo_params algo_params[2];
  211. uint32_t size = 0;
  212. long long start_ms;
  213. long long elapsed_ms;
  214. uint32_t address;
  215. uint32_t index;
  216. int retval;
  217. if (TARGET_HALTED != target->state) {
  218. LOG_ERROR("Target not halted");
  219. return ERROR_TARGET_NOT_HALTED;
  220. }
  221. retval = cc2538_init(bank);
  222. if (ERROR_OK != retval)
  223. return retval;
  224. /* Initialize algorithm parameters to default values */
  225. buf_set_u32(algo_params[0].command, 0, 32, CC2538_CMD_PROGRAM);
  226. buf_set_u32(algo_params[1].command, 0, 32, CC2538_CMD_PROGRAM);
  227. /* Write requested data, ping-ponging between two buffers */
  228. index = 0;
  229. start_ms = timeval_ms();
  230. address = bank->base + offset;
  231. while (count > 0) {
  232. if (count > CC2538_SECTOR_LENGTH)
  233. size = CC2538_SECTOR_LENGTH;
  234. else
  235. size = count;
  236. /* Put next block of data to flash into buffer */
  237. retval = target_write_buffer(target, cc2538_bank->buffer_addr[index],
  238. size, buffer);
  239. if (ERROR_OK != retval) {
  240. LOG_ERROR("Unable to write data to target memory");
  241. break;
  242. }
  243. /* Update algo parameters for next block */
  244. buf_set_u32(algo_params[index].address, 0, 32, address);
  245. buf_set_u32(algo_params[index].length, 0, 32, size);
  246. buf_set_u32(algo_params[index].status, 0, 32, CC2538_BUFFER_FULL);
  247. /* Issue flash helper algorithm parameters for block write */
  248. retval = target_write_buffer(target, cc2538_bank->params_addr[index],
  249. sizeof(algo_params[index]), (uint8_t *)&algo_params[index]);
  250. if (ERROR_OK != retval)
  251. break;
  252. /* Wait for next ping pong buffer to be ready */
  253. index ^= 1;
  254. retval = cc2538_wait_algo_done(bank, cc2538_bank->params_addr[index]);
  255. if (ERROR_OK != retval)
  256. break;
  257. count -= size;
  258. buffer += size;
  259. address += size;
  260. elapsed_ms = timeval_ms() - start_ms;
  261. if (elapsed_ms > 500)
  262. keep_alive();
  263. }
  264. /* If no error yet, wait for last buffer to finish */
  265. if (ERROR_OK == retval) {
  266. index ^= 1;
  267. retval = cc2538_wait_algo_done(bank, cc2538_bank->params_addr[index]);
  268. }
  269. /* Regardless of errors, try to close down algo */
  270. (void)cc2538_quit(bank);
  271. return retval;
  272. }
  273. static int cc2538_probe(struct flash_bank *bank)
  274. {
  275. struct target *target = bank->target;
  276. struct cc2538_bank *cc2538_bank = bank->driver_priv;
  277. uint32_t value;
  278. int num_sectors;
  279. int retval;
  280. retval = target_read_u32(target, CC2538_FLASH_CTRL_DIECFG0, &value);
  281. if (ERROR_OK != retval)
  282. return retval;
  283. cc2538_bank->chip_id = value >> 16;
  284. num_sectors = ((value & 0x70) >> 4) * 0x20000 / CC2538_SECTOR_LENGTH;
  285. if (num_sectors > CC2538_MAX_SECTORS)
  286. num_sectors = CC2538_MAX_SECTORS;
  287. bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
  288. if (NULL == bank->sectors)
  289. return ERROR_FAIL;
  290. /* Set up flash helper algorithm */
  291. cc2538_bank->algo_code = cc2538_algo;
  292. cc2538_bank->algo_size = sizeof(cc2538_algo);
  293. cc2538_bank->algo_working_size = CC2538_WORKING_SIZE;
  294. cc2538_bank->buffer_addr[0] = CC2538_ALGO_BUFFER_0;
  295. cc2538_bank->buffer_addr[1] = CC2538_ALGO_BUFFER_1;
  296. cc2538_bank->params_addr[0] = CC2538_ALGO_PARAMS_0;
  297. cc2538_bank->params_addr[1] = CC2538_ALGO_PARAMS_1;
  298. bank->base = CC2538_FLASH_BASE_ADDR;
  299. bank->num_sectors = num_sectors;
  300. bank->size = num_sectors * CC2538_SECTOR_LENGTH;
  301. bank->write_start_alignment = 0;
  302. bank->write_end_alignment = 0;
  303. for (int i = 0; i < num_sectors; i++) {
  304. bank->sectors[i].offset = i * CC2538_SECTOR_LENGTH;
  305. bank->sectors[i].size = CC2538_SECTOR_LENGTH;
  306. bank->sectors[i].is_erased = -1;
  307. bank->sectors[i].is_protected = 0;
  308. }
  309. /* We've successfully determined the stats on the flash bank */
  310. cc2538_bank->probed = true;
  311. /* If we fall through to here, then all went well */
  312. return ERROR_OK;
  313. }
  314. static int cc2538_auto_probe(struct flash_bank *bank)
  315. {
  316. struct cc2538_bank *cc2538_bank = bank->driver_priv;
  317. int retval = ERROR_OK;
  318. if (!cc2538_bank->probed)
  319. retval = cc2538_probe(bank);
  320. return retval;
  321. }
  322. static int cc2538_info(struct flash_bank *bank, char *buf, int buf_size)
  323. {
  324. struct cc2538_bank *cc2538_bank = bank->driver_priv;
  325. int printed = 0;
  326. printed = snprintf(buf, buf_size,
  327. "cc2538 device: chip ID 0x%04x\n", cc2538_bank->chip_id);
  328. if (printed >= buf_size)
  329. return ERROR_BUF_TOO_SMALL;
  330. return ERROR_OK;
  331. }
  332. const struct flash_driver cc2538_flash = {
  333. .name = "cc2538",
  334. .flash_bank_command = cc2538_flash_bank_command,
  335. .erase = cc2538_erase,
  336. .write = cc2538_write,
  337. .read = default_flash_read,
  338. .probe = cc2538_probe,
  339. .auto_probe = cc2538_auto_probe,
  340. .erase_check = default_flash_blank_check,
  341. .info = cc2538_info,
  342. .free_driver_priv = default_flash_free_driver_priv,
  343. };