dsp5680xx - indent fix
[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 following the execution of this function.
125  * 
126  * @param bank 
127  * @param set Apply or remove security on the chip.
128  * @param first This parameter is ignored.
129  * @param last This parameter is ignored.
130  * 
131  * @return 
132  */
133 static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, int first,
134                                    int last)
135 {
136 /**
137  * This applies security to flash module after next reset, it does
138  * not actually apply protection (protection refers to undesired access from the core)
139  */
140         int retval;
141
142         if (set)
143                 retval = dsp5680xx_f_lock(bank->target);
144         else {
145                 retval = dsp5680xx_f_unlock(bank->target);
146                 if (retval == ERROR_OK) {
147                         /* mark all as erased */
148                         for (int i = 0; i <= (HFM_SECTOR_COUNT - 1); i++)
149                                 /* FM does not recognize it as erased if erased via JTAG. */
150                                 bank->sectors[i].is_erased = 1;
151                 }
152         }
153         return retval;
154 }
155
156 /** 
157  * The dsp5680xx use word addressing. The "/2" that appear in the following code are a workaround for the fact that OpenOCD uses byte addressing.
158  * 
159  * @param bank 
160  * @param buffer Data to write to flash.
161  * @param offset 
162  * @param count In bytes (2 bytes per address).
163  * 
164  * @return 
165  */
166 static int dsp5680xx_flash_write(struct flash_bank *bank, uint8_t * buffer,
167                                  uint32_t offset, uint32_t count)
168 {
169         int retval;
170
171         if ((offset + count / 2) > bank->size) {
172                 LOG_ERROR("%s: Flash bank cannot fit data.", __func__);
173                 return ERROR_FAIL;
174         }
175         if (offset % 2) {
176                 /**
177                  * Writing to odd addresses not supported.
178                  * This chip uses word addressing, Openocd only supports byte addressing.
179                  * The workaround results in disabling writing to odd byte addresses
180                  */
181                 LOG_ERROR
182                     ("%s: Writing to odd addresses not supported for this target",
183                      __func__);
184                 return ERROR_FAIL;
185         }
186         retval =
187             dsp5680xx_f_wr(bank->target, buffer, bank->base + offset / 2, count,
188                            0);
189         uint32_t addr_word;
190
191         for (addr_word = bank->base + offset / 2; addr_word < count / 2;
192              addr_word += (HFM_SECTOR_SIZE / 2)) {
193                 if (retval == ERROR_OK)
194                         bank->sectors[addr_word /
195                                       (HFM_SECTOR_SIZE / 2)].is_erased = 0;
196                 else
197                         bank->sectors[addr_word /
198                                       (HFM_SECTOR_SIZE / 2)].is_erased = -1;
199         }
200         return retval;
201 }
202
203 static int dsp5680xx_probe(struct flash_bank *bank)
204 {
205         LOG_DEBUG("%s not implemented", __func__);
206         return ERROR_OK;
207 }
208
209 static int dsp5680xx_flash_info(struct flash_bank *bank, char *buf,
210                                 int buf_size)
211 {
212         snprintf(buf, buf_size,
213                 "\ndsp5680xx flash driver info:\n - See comments in code.");
214         return ERROR_OK;
215 }
216
217 /** 
218  * The flash module (FM) on the dsp5680xx supports both individual sector and mass erase of the flash memory.
219  * If this function is called with @first == @last == 0 or if @first is the first sector (#0) and @last is the last sector then the mass erase command is executed (much faster than erasing each sector individually).
220  * 
221  * @param bank 
222  * @param first 
223  * @param last 
224  * 
225  * @return 
226  */
227 static int dsp5680xx_flash_erase(struct flash_bank *bank, int first, int last)
228 {
229         int retval;
230
231         retval =
232             dsp5680xx_f_erase(bank->target, (uint32_t) first, (uint32_t) last);
233         if ((!(first | last))
234             || ((first == 0) && (last == (HFM_SECTOR_COUNT - 1))))
235                 last = HFM_SECTOR_COUNT - 1;
236         if (retval == ERROR_OK)
237                 for (int i = first; i <= last; i++)
238                         bank->sectors[i].is_erased = 1;
239         else
240                 /**
241                  * If an error occurred unknown status
242                  *is set even though some sector could have been correctly erased.
243                  */
244                 for (int i = first; i <= last; i++)
245                         bank->sectors[i].is_erased = -1;
246         return retval;
247 }
248
249 /** 
250  * The flash module (FM) on the dsp5680xx support a blank check function.
251  * This function executes the FM's blank check functionality on each and every sector.
252  * 
253  * @param bank 
254  * 
255  * @return 
256  */
257 static int dsp5680xx_flash_erase_check(struct flash_bank *bank)
258 {
259         int retval = ERROR_OK;
260
261         uint8_t erased = 0;
262
263         uint32_t i;
264
265         for (i = 0; i < HFM_SECTOR_COUNT; i++) {
266                 if (bank->sectors[i].is_erased == -1) {
267                         retval =
268                             dsp5680xx_f_erase_check(bank->target, &erased, i);
269                         if (retval != ERROR_OK) {
270                                 bank->sectors[i].is_erased = -1;
271                         } else {
272                                 if (erased)
273                                         bank->sectors[i].is_erased = 1;
274                                 else
275                                         bank->sectors[i].is_erased = 0;
276                         }
277                 }
278         }
279         return retval;
280 }
281
282 struct flash_driver dsp5680xx_flash = {
283         .name = "dsp5680xx_flash",
284         .flash_bank_command = dsp5680xx_flash_bank_command,
285         .erase = dsp5680xx_flash_erase,
286         .protect = dsp5680xx_flash_protect,
287         .write = dsp5680xx_flash_write,
288         /* .read = default_flash_read, */
289         .probe = dsp5680xx_probe,
290         .auto_probe = dsp5680xx_probe,
291         .erase_check = dsp5680xx_flash_erase_check,
292         .protect_check = dsp5680xx_flash_protect_check,
293         .info = dsp5680xx_flash_info
294 };