ef3a4fccf60871f3579bbd5b9f25a84cc5dc3515
[fw/openocd] / contrib / loaders / flash / cc26xx / flashloader.c
1 /* SPDX-License-Identifier: BSD-3-Clause */
2
3 /******************************************************************************
4 *
5 * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
6 *
7 ******************************************************************************/
8
9 #include <stdint.h>
10 #include <stdbool.h>
11 #include "flashloader.h"
12 #include "flash.h"
13
14 /* Array holding erased state of the flash sectors. */
15 static bool g_is_erased[FLASH_MAX_SECTOR_COUNT];
16
17 extern uint8_t g_retain_buf[];
18
19 uint32_t flashloader_init(struct flash_params *params, uint8_t *buf1,
20         uint8_t *buf2)
21 {
22         /* Initialize params buffers */
23         memset((void *)params, 0, 2 * sizeof(struct flash_params));
24         params[0].buf_addr = (uint32_t)buf1;
25         params[1].buf_addr = (uint32_t)buf2;
26
27         /* Mark all sectors at "not erased" */
28         memset(g_is_erased, false, sizeof(g_is_erased));
29
30         return STATUS_OK;
31 }
32
33 uint32_t flashloader_erase_and_program(uint8_t *src, uint32_t address,
34         uint32_t byte_count)
35 {
36         if (byte_count > BUFFER_LEN)
37                 return STATUS_FAILED_INVALID_ARGUMENTS;
38
39         /* Erase affected sectors */
40         uint32_t status = flashloader_erase_sectors(address, byte_count);
41
42         if (status != STATUS_OK)
43                 return status;
44
45         /* Program data */
46         status = flashloader_program(src, address, byte_count);
47
48         return status;
49 }
50
51 uint32_t flashloader_program_with_retain(uint8_t *src, uint32_t address,
52         uint32_t byte_count)
53 {
54 #if (BUFFER_LEN > FLASH_ERASE_SIZE)
55 #error Buffer size cannot be larger than the flash sector size!
56 #endif
57
58         uint32_t first_sector_idx;
59         uint32_t last_sector_idx;
60         uint32_t status = STATUS_OK;
61         uint32_t i;
62
63         first_sector_idx = flashloader_address_to_sector(address);
64         last_sector_idx = flashloader_address_to_sector(address + byte_count - 1);
65
66         /* Mark all sectors as "not erased" before starting */
67         memset(g_is_erased, false, sizeof(g_is_erased));
68
69         uint32_t sec_offset = address % FLASH_ERASE_SIZE;
70         uint32_t curr_count;
71         uint32_t src_offset = 0;
72
73         for (i = first_sector_idx; i <= last_sector_idx; i++) {
74
75                 /* Chop off at sector boundary if data goes into the next sector. */
76                 curr_count = byte_count;
77                 if ((address + byte_count) > ((i+1) * FLASH_ERASE_SIZE))
78                         curr_count -= (address + byte_count) % FLASH_ERASE_SIZE;
79
80                 /* Copy flash sector to retain buffer */
81                 memcpy(g_retain_buf, (void *)(i * FLASH_ERASE_SIZE), FLASH_ERASE_SIZE);
82
83                 /* Copy data buffer to retain buffer */
84                 memcpy(&g_retain_buf[sec_offset], &src[src_offset], curr_count);
85
86                 /* Erase and program from retain buffer */
87                 status = flashloader_erase_and_program(g_retain_buf,
88                                         (i * FLASH_ERASE_SIZE), FLASH_ERASE_SIZE);
89                 if (status != STATUS_OK)
90                         return status;
91
92                 address += curr_count;
93                 sec_offset = address % FLASH_ERASE_SIZE;
94                 byte_count -= curr_count;
95                 src_offset += curr_count;
96         }
97
98         return status;
99 }
100
101 uint32_t flashloader_erase_all(void)
102 {
103         if (flash_bank_erase(true) != FAPI_STATUS_SUCCESS)
104                 return STATUS_FAILED_ERASE_ALL;
105
106         memset(g_is_erased, true, sizeof(g_is_erased));
107
108         return STATUS_OK;
109 }
110
111 uint32_t flashloader_erase_sectors(uint32_t address, uint32_t byte_count)
112 {
113         uint32_t first_sector_idx;
114         uint32_t last_sector_idx;
115         uint32_t status;
116         uint32_t idx;
117
118         /* Floor address to the start of the sector and convert to sector number */
119         first_sector_idx = flashloader_address_to_sector(address);
120         last_sector_idx = flashloader_address_to_sector(address + byte_count - 1);
121
122         /*  Erase given sector(s) */
123         for (idx = first_sector_idx; idx <= last_sector_idx; idx++) {
124
125                 /* Only erase sectors that haven't already been erased */
126                 if (g_is_erased[idx] == false) {
127                         status = flash_sector_erase(idx * FLASH_ERASE_SIZE);
128                         if (status != FAPI_STATUS_SUCCESS) {
129                                 status = (STATUS_FAILED_SECTOR_ERASE |
130                                                 ((idx << STATUS_EXT_INFO_S) & STATUS_EXT_INFO_M) |
131                                                 ((status << STATUS_ROM_CODE_S) & STATUS_ROM_CODE_M));
132                                 return status;
133                         }
134                         g_is_erased[idx] = true;
135                 }
136         }
137
138         return STATUS_OK;
139 }
140
141 uint32_t flashloader_program(uint8_t *src, uint32_t address,
142         uint32_t byte_count)
143 {
144         uint32_t status = flash_program(src, address, byte_count);
145         if (status != FAPI_STATUS_SUCCESS) {
146                 status = (STATUS_FAILED_PROGRAM |
147                                         ((status << STATUS_ROM_CODE_S) & STATUS_ROM_CODE_M));
148         }
149
150         return STATUS_OK;
151 }