2eaf618647459faef0717aa4b926e08953602565
[fw/openocd] / contrib / loaders / flash / cc26xx / flashloader.c
1 /******************************************************************************
2 *
3 * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 *  Redistributions of source code must retain the above copyright
10 *  notice, this list of conditions and the following disclaimer.
11 *
12 *  Redistributions in binary form must reproduce the above copyright
13 *  notice, this list of conditions and the following disclaimer in the
14 *  documentation and/or other materials provided with the
15 *  distribution.
16 *
17 *  Neither the name of Texas Instruments Incorporated nor the names of
18 *  its contributors may be used to endorse or promote products derived
19 *  from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 ******************************************************************************/
34
35 #include <stdint.h>
36 #include <stdbool.h>
37 #include "flashloader.h"
38 #include "flash.h"
39
40 /* Array holding erased state of the flash sectors. */
41 static bool g_is_erased[FLASH_MAX_SECTOR_COUNT];
42
43 extern uint8_t g_retain_buf[];
44
45 uint32_t flashloader_init(struct flash_params *params, uint8_t *buf1,
46         uint8_t *buf2)
47 {
48         /* Initialize params buffers */
49         memset((void *)params, 0, 2 * sizeof(struct flash_params));
50         params[0].buf_addr = (uint32_t)buf1;
51         params[1].buf_addr = (uint32_t)buf2;
52
53         /* Mark all sectors at "not erased" */
54         memset(g_is_erased, false, sizeof(g_is_erased));
55
56         return STATUS_OK;
57 }
58
59 uint32_t flashloader_erase_and_program(uint8_t *src, uint32_t address,
60         uint32_t byte_count)
61 {
62         if (byte_count > BUFFER_LEN)
63                 return STATUS_FAILED_INVALID_ARGUMENTS;
64
65         /* Erase affected sectors */
66         uint32_t status = flashloader_erase_sectors(address, byte_count);
67
68         if (status != STATUS_OK)
69                 return status;
70
71         /* Program data */
72         status = flashloader_program(src, address, byte_count);
73
74         return status;
75 }
76
77 uint32_t flashloader_program_with_retain(uint8_t *src, uint32_t address,
78         uint32_t byte_count)
79 {
80 #if (BUFFER_LEN > FLASH_ERASE_SIZE)
81 #error Buffer size cannot be larger than the flash sector size!
82 #endif
83
84         uint32_t first_sector_idx;
85         uint32_t last_sector_idx;
86         uint32_t status = STATUS_OK;
87         uint32_t i;
88
89         first_sector_idx = flashloader_address_to_sector(address);
90         last_sector_idx = flashloader_address_to_sector(address + byte_count - 1);
91
92         /* Mark all sectors as "not erased" before starting */
93         memset(g_is_erased, false, sizeof(g_is_erased));
94
95         uint32_t sec_offset = address % FLASH_ERASE_SIZE;
96         uint32_t curr_count;
97         uint32_t src_offset = 0;
98
99         for (i = first_sector_idx; i <= last_sector_idx; i++) {
100
101                 /* Chop off at sector boundary if data goes into the next sector. */
102                 curr_count = byte_count;
103                 if ((address + byte_count) > ((i+1) * FLASH_ERASE_SIZE))
104                         curr_count -= (address + byte_count) % FLASH_ERASE_SIZE;
105
106                 /* Copy flash sector to retain buffer */
107                 memcpy(g_retain_buf, (void *)(i * FLASH_ERASE_SIZE), FLASH_ERASE_SIZE);
108
109                 /* Copy data buffer to retain buffer */
110                 memcpy(&g_retain_buf[sec_offset], &src[src_offset], curr_count);
111
112                 /* Erase and program from retain buffer */
113                 status = flashloader_erase_and_program(g_retain_buf,
114                                         (i * FLASH_ERASE_SIZE), FLASH_ERASE_SIZE);
115                 if (status != STATUS_OK)
116                         return status;
117
118                 address += curr_count;
119                 sec_offset = address % FLASH_ERASE_SIZE;
120                 byte_count -= curr_count;
121                 src_offset += curr_count;
122         }
123
124         return status;
125 }
126
127 uint32_t flashloader_erase_all(void)
128 {
129         if (flash_bank_erase(true) != FAPI_STATUS_SUCCESS)
130                 return STATUS_FAILED_ERASE_ALL;
131
132         memset(g_is_erased, true, sizeof(g_is_erased));
133
134         return STATUS_OK;
135 }
136
137 uint32_t flashloader_erase_sectors(uint32_t address, uint32_t byte_count)
138 {
139         uint32_t first_sector_idx;
140         uint32_t last_sector_idx;
141         uint32_t status;
142         uint32_t idx;
143
144         /* Floor address to the start of the sector and convert to sector number */
145         first_sector_idx = flashloader_address_to_sector(address);
146         last_sector_idx = flashloader_address_to_sector(address + byte_count - 1);
147
148         /*  Erase given sector(s) */
149         for (idx = first_sector_idx; idx <= last_sector_idx; idx++) {
150
151                 /* Only erase sectors that haven't already been erased */
152                 if (g_is_erased[idx] == false) {
153                         status = flash_sector_erase(idx * FLASH_ERASE_SIZE);
154                         if (status != FAPI_STATUS_SUCCESS) {
155                                 status = (STATUS_FAILED_SECTOR_ERASE |
156                                                 ((idx << STATUS_EXT_INFO_S) & STATUS_EXT_INFO_M) |
157                                                 ((status << STATUS_ROM_CODE_S) & STATUS_ROM_CODE_M));
158                                 return status;
159                         }
160                         g_is_erased[idx] = true;
161                 }
162         }
163
164         return STATUS_OK;
165 }
166
167 uint32_t flashloader_program(uint8_t *src, uint32_t address,
168         uint32_t byte_count)
169 {
170         uint32_t status = flash_program(src, address, byte_count);
171         if (status != FAPI_STATUS_SUCCESS) {
172                 status = (STATUS_FAILED_PROGRAM |
173                                         ((status << STATUS_ROM_CODE_S) & STATUS_ROM_CODE_M));
174         }
175
176         return STATUS_OK;
177 }