eb2f3e1b3782478f7523c1355ab3bb12fae235c8
[fw/openocd] / src / flash / nor / dsp5680xx_flash.c
1 /***************************************************************************
2  *   Copyright (C) 2011 by Rodrigo L. Rosa                                 *
3  *   rodrigorosa.LG@gmail.com                                              *
4  *                                                                         *
5  *   Based on a file written by:                                           *
6  *   Kevin McGuire                                                         *
7  *   Marcel Wijlaars                                                       *
8  *   Michael Ashton                                                        *
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  *   This program is distributed in the hope that it will be useful,       *
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18  *   GNU General Public License for more details.                          *
19  *                                                                         *
20  *   You should have received a copy of the GNU General Public License     *
21  *   along with this program; if not, write to the                         *
22  *   Free Software Foundation, Inc.,                                       *
23  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
24  ***************************************************************************/
25
26 /**
27  * @file   dsp5680xx_flash.c
28  * @author Rodrigo L. Rosa <rodrigorosa.LG@gmail.com>
29  * @date   Thu Jun  9 18:21:58 2011
30  *
31  * @brief  This file implements the basic functions to run flashing commands
32  * from the TCL interface.
33  * It allows the user to flash the Freescale 5680xx DSP.
34  *
35  *
36  */
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include "imp.h"
43 #include <helper/binarybuffer.h>
44 #include <helper/time_support.h>
45 #include <target/algorithm.h>
46 #include <target/dsp5680xx.h>
47
48 struct dsp5680xx_flash_bank {
49         struct working_area *write_algorithm;
50 };
51
52 static int dsp5680xx_build_sector_list(struct flash_bank *bank)
53 {
54         uint32_t offset = HFM_FLASH_BASE_ADDR;
55
56         bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
57         int i;
58
59         for (i = 0; i < bank->num_sectors; ++i) {
60                 bank->sectors[i].offset = i * HFM_SECTOR_SIZE;
61                 bank->sectors[i].size = HFM_SECTOR_SIZE;
62                 offset += bank->sectors[i].size;
63                 bank->sectors[i].is_erased = -1;
64                 bank->sectors[i].is_protected = -1;
65         }
66         LOG_USER("%s not tested yet.", __func__);
67         return ERROR_OK;
68
69 }
70
71 /* flash bank dsp5680xx 0 0 0 0 <target#> */
72 FLASH_BANK_COMMAND_HANDLER(dsp5680xx_flash_bank_command)
73 {
74         struct dsp5680xx_flash_bank *nbank;
75
76         nbank = malloc(sizeof(struct dsp5680xx_flash_bank));
77
78         bank->base = HFM_FLASH_BASE_ADDR;
79         bank->size = HFM_SIZE_BYTES; /* top 4k not accessible */
80         bank->driver_priv = nbank;
81         bank->num_sectors = HFM_SECTOR_COUNT;
82         dsp5680xx_build_sector_list(bank);
83
84         return ERROR_OK;
85 }
86
87 /**
88  * A memory mapped register (PROT) holds information regarding sector protection.
89  * Protection refers to undesired core access.
90  * The value in this register is loaded from flash upon reset.
91  *
92  * @param bank
93  *
94  * @return
95  */
96 static int dsp5680xx_flash_protect_check(struct flash_bank *bank)
97 {
98         int retval = ERROR_OK;
99
100         uint16_t protected = 0;
101
102         retval = dsp5680xx_f_protect_check(bank->target, &protected);
103         if (retval != ERROR_OK) {
104                 for (int i = 0; i < HFM_SECTOR_COUNT; i++)
105                         bank->sectors[i].is_protected = -1;
106                 return ERROR_OK;
107         }
108         for (int i = 0; i < HFM_SECTOR_COUNT / 2; i++) {
109                 if (protected & 1) {
110                         bank->sectors[2 * i].is_protected = 1;
111                         bank->sectors[2 * i + 1].is_protected = 1;
112                 } else {
113                         bank->sectors[2 * i].is_protected = 0;
114                         bank->sectors[2 * i + 1].is_protected = 0;
115                 }
116                 protected = (protected >> 1);
117         }
118         return retval;
119 }
120
121 /**
122  * Protection funcionality is not implemented.
123  * The current implementation applies/removes security on the chip.
124  * The chip is effectively secured/unsecured after the first reset
125  * following the execution of this function.
126  *
127  * @param bank
128  * @param set Apply or remove security on the chip.
129  * @param first This parameter is ignored.
130  * @param last This parameter is ignored.
131  *
132  * @return
133  */
134 static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, int first,
135                                    int last)
136 {
137 /**
138  * This applies security to flash module after next reset, it does
139  * not actually apply protection (protection refers to undesired access from the core)
140  */
141         int retval;
142
143         if (set)
144                 retval = dsp5680xx_f_lock(bank->target);
145         else {
146                 retval = dsp5680xx_f_unlock(bank->target);
147                 if (retval == ERROR_OK) {
148                         /* mark all as erased */
149                         for (int i = 0; i <= (HFM_SECTOR_COUNT - 1); i++)
150                                 /* FM does not recognize it as erased if erased via JTAG. */
151                                 bank->sectors[i].is_erased = 1;
152                 }
153         }
154         return retval;
155 }
156
157 /**
158  * The dsp5680xx use word addressing. The "/2" that appear in the following code
159  * are a workaround for the fact that OpenOCD uses byte addressing.
160  *
161  * @param bank
162  * @param buffer Data to write to flash.
163  * @param offset
164  * @param count In bytes (2 bytes per address).
165  *
166  * @return
167  */
168 static int dsp5680xx_flash_write(struct flash_bank *bank, uint8_t * buffer,
169                                  uint32_t offset, uint32_t count)
170 {
171         int retval;
172
173         if ((offset + count / 2) > bank->size) {
174                 LOG_ERROR("%s: Flash bank cannot fit data.", __func__);
175                 return ERROR_FAIL;
176         }
177         if (offset % 2) {
178                 /**
179                  * Writing to odd addresses not supported.
180                  * This chip uses word addressing, Openocd only supports byte addressing.
181                  * The workaround results in disabling writing to odd byte addresses
182                  */
183                 LOG_ERROR("%s: Writing to odd addresses not supported for this target", __func__);
184                 return ERROR_FAIL;
185         }
186         retval = dsp5680xx_f_wr(bank->target, buffer, bank->base + offset / 2, count, 0);
187         uint32_t addr_word;
188
189         for (addr_word = bank->base + offset / 2; addr_word < count / 2;
190                         addr_word += (HFM_SECTOR_SIZE / 2)) {
191                 if (retval == ERROR_OK)
192                         bank->sectors[addr_word / (HFM_SECTOR_SIZE / 2)].is_erased = 0;
193                 else
194                         bank->sectors[addr_word / (HFM_SECTOR_SIZE / 2)].is_erased = -1;
195         }
196         return retval;
197 }
198
199 static int dsp5680xx_probe(struct flash_bank *bank)
200 {
201         LOG_DEBUG("%s not implemented", __func__);
202         return ERROR_OK;
203 }
204
205 static int dsp5680xx_flash_info(struct flash_bank *bank, char *buf,
206                 int buf_size)
207 {
208         snprintf(buf, buf_size,
209                 "\ndsp5680xx flash driver info:\n - See comments in code.");
210         return ERROR_OK;
211 }
212
213 /**
214  * The flash module (FM) on the dsp5680xx supports both individual sector
215  * and mass erase of the flash memory.
216  * If this function is called with @first == @last == 0 or if @first is the
217  * first sector (#0) and @last is the last sector then the mass erase command
218  * is executed (much faster than erasing each sector individually).
219  *
220  * @param bank
221  * @param first
222  * @param last
223  *
224  * @return
225  */
226 static int dsp5680xx_flash_erase(struct flash_bank *bank, int first, int last)
227 {
228         int retval;
229
230         retval = dsp5680xx_f_erase(bank->target, (uint32_t) first, (uint32_t) last);
231         if ((!(first | last)) || ((first == 0) && (last == (HFM_SECTOR_COUNT - 1))))
232                 last = HFM_SECTOR_COUNT - 1;
233         if (retval == ERROR_OK)
234                 for (int i = first; i <= last; i++)
235                         bank->sectors[i].is_erased = 1;
236         else
237                 /**
238                  * If an error occurred unknown status
239                  *is set even though some sector could have been correctly erased.
240                  */
241                 for (int i = first; i <= last; i++)
242                         bank->sectors[i].is_erased = -1;
243         return retval;
244 }
245
246 /**
247  * The flash module (FM) on the dsp5680xx support a blank check function.
248  * This function executes the FM's blank check functionality on each and every sector.
249  *
250  * @param bank
251  *
252  * @return
253  */
254 static int dsp5680xx_flash_erase_check(struct flash_bank *bank)
255 {
256         int retval = ERROR_OK;
257
258         uint8_t erased = 0;
259
260         uint32_t i;
261
262         for (i = 0; i < HFM_SECTOR_COUNT; i++) {
263                 if (bank->sectors[i].is_erased == -1) {
264                         retval = dsp5680xx_f_erase_check(bank->target, &erased, i);
265                         if (retval != ERROR_OK) {
266                                 bank->sectors[i].is_erased = -1;
267                         } else {
268                                 if (erased)
269                                         bank->sectors[i].is_erased = 1;
270                                 else
271                                         bank->sectors[i].is_erased = 0;
272                         }
273                 }
274         }
275         return retval;
276 }
277
278 struct flash_driver dsp5680xx_flash = {
279         .name = "dsp5680xx_flash",
280         .flash_bank_command = dsp5680xx_flash_bank_command,
281         .erase = dsp5680xx_flash_erase,
282         .protect = dsp5680xx_flash_protect,
283         .write = dsp5680xx_flash_write,
284         /* .read = default_flash_read, */
285         .probe = dsp5680xx_probe,
286         .auto_probe = dsp5680xx_probe,
287         .erase_check = dsp5680xx_flash_erase_check,
288         .protect_check = dsp5680xx_flash_protect_check,
289         .info = dsp5680xx_flash_info
290 };