move nor drivers to src/flash/nor
[openocd.git] / src / flash / nor / ocl.c
1 /***************************************************************************
2 * Copyright (C) 2007 by Pavel Chromy *
3 * chromy@asix.cz *
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, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "ocl.h"
25 #include "flash.h"
26 #include "embeddedice.h"
27
28
29 struct ocl_priv
30 {
31 struct arm_jtag *jtag_info;
32 unsigned int buflen;
33 unsigned int bufalign;
34 };
35
36 static int ocl_erase_check(struct flash_bank *bank)
37 {
38 return ERROR_OK;
39 }
40
41 static int ocl_protect_check(struct flash_bank *bank)
42 {
43 return ERROR_OK;
44 }
45
46 /* flash_bank ocl 0 0 0 0 <target#> */
47 FLASH_BANK_COMMAND_HANDLER(ocl_flash_bank_command)
48 {
49 struct arm7_9_common *arm7_9;
50 struct ocl_priv *ocl;
51
52 if (CMD_ARGC < 6)
53 {
54 LOG_WARNING("incomplete flash_bank ocl configuration");
55 return ERROR_FLASH_BANK_INVALID;
56 }
57
58 arm7_9 = target_to_arm7_9(bank->target);
59 if (!is_arm7_9(arm7_9))
60 return ERROR_TARGET_INVALID;
61
62 ocl = bank->driver_priv = malloc(sizeof(struct ocl_priv));
63 ocl->jtag_info = &arm7_9->jtag_info;
64 ocl->buflen = 0;
65 ocl->bufalign = 1;
66
67 return ERROR_OK;
68 }
69
70 static int ocl_erase(struct flash_bank *bank, int first, int last)
71 {
72 struct ocl_priv *ocl = bank->driver_priv;
73 int retval;
74 uint32_t dcc_buffer[3];
75
76 /* check preconditions */
77 if (bank->num_sectors == 0)
78 return ERROR_FLASH_BANK_NOT_PROBED;
79
80 if (bank->target->state != TARGET_RUNNING)
81 {
82 LOG_ERROR("target has to be running to communicate with the loader");
83 return ERROR_TARGET_NOT_RUNNING;
84 }
85
86 if ((first == 0) && (last == bank->num_sectors - 1))
87 {
88 dcc_buffer[0] = OCL_ERASE_ALL;
89 if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
90 return retval;
91 }
92 else
93 {
94 dcc_buffer[0] = OCL_ERASE_BLOCK;
95 dcc_buffer[1] = first;
96 dcc_buffer[2] = last;
97 if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 3) != ERROR_OK))
98 return retval;
99 }
100
101 /* wait for response, fixed timeout of 1 s */
102 if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
103 {
104 if (retval == ERROR_TARGET_TIMEOUT)
105 LOG_ERROR("loader not responding");
106 return retval;
107 }
108
109 /* receive response */
110 if ((retval = embeddedice_receive(ocl->jtag_info, dcc_buffer + 1, 1) != ERROR_OK))
111 return retval;
112
113 if (dcc_buffer[1] != OCL_CMD_DONE)
114 {
115 if (dcc_buffer[0] == OCL_ERASE_ALL)
116 LOG_ERROR("loader response to OCL_ERASE_ALL 0x%08" PRIx32 "", dcc_buffer[1]);
117 else
118 LOG_ERROR("loader response to OCL_ERASE_BLOCK 0x%08" PRIx32 "", dcc_buffer[1]);
119 return ERROR_FLASH_OPERATION_FAILED;
120 }
121
122 return ERROR_OK;
123 }
124
125 static int ocl_protect(struct flash_bank *bank, int set, int first, int last)
126 {
127 return ERROR_OK;
128 }
129
130 static int ocl_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
131 {
132 struct ocl_priv *ocl = bank->driver_priv;
133 int retval;
134 uint32_t *dcc_buffer;
135 uint32_t *dcc_bufptr;
136 int byteofs;
137 int runlen;
138 uint32_t chksum;
139
140 int i;
141
142 /* check preconditions */
143 if (ocl->buflen == 0 || ocl->bufalign == 0)
144 return ERROR_FLASH_BANK_NOT_PROBED;
145
146 if (bank->target->state != TARGET_RUNNING)
147 {
148 LOG_ERROR("target has to be running to communicate with the loader");
149 return ERROR_TARGET_NOT_RUNNING;
150 }
151
152 /* allocate buffer for max. ocl buffer + overhead */
153 dcc_buffer = malloc(sizeof(uint32_t)*(ocl->buflen/4 + 3));
154
155 while (count)
156 {
157 if (count + (offset % ocl->bufalign) > ocl->buflen)
158 runlen = ocl->buflen - (offset % ocl->bufalign);
159 else
160 runlen = count;
161
162 dcc_buffer[0] = OCL_FLASH_BLOCK | runlen;
163 dcc_buffer[1] = offset;
164 dcc_bufptr = &dcc_buffer[2];
165
166 *dcc_bufptr = 0xffffffff;
167 byteofs = (offset % ocl->bufalign) % 4;
168 chksum = OCL_CHKS_INIT;
169
170 /* copy data to DCC buffer in proper byte order and properly aligned */
171 for (i = 0; i < runlen; i++)
172 {
173 switch (byteofs++)
174 {
175 case 0:
176 *dcc_bufptr &= *(buffer++) | 0xffffff00;
177 break;
178 case 1:
179 *dcc_bufptr &= ((*(buffer++)) << 8) | 0xffff00ff;
180 break;
181 case 2:
182 *dcc_bufptr &= ((*(buffer++)) << 16) | 0xff00ffff;
183 break;
184 case 3:
185 *dcc_bufptr &= ((*(buffer++)) << 24) | 0x00ffffff;
186 chksum ^= *(dcc_bufptr++);
187 *dcc_bufptr = 0xffffffff;
188 byteofs = 0;
189 break;
190 }
191 }
192
193 /* add the remaining word to checksum */
194 if (byteofs)
195 chksum ^= *(dcc_bufptr++);
196
197 *(dcc_bufptr++) = chksum;
198
199 /* send the data */
200 if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, dcc_bufptr-dcc_buffer)) != ERROR_OK)
201 {
202 free(dcc_buffer);
203 return retval;
204 }
205
206 /* wait for response, fixed timeout of 1 s */
207 if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
208 {
209 if (retval == ERROR_TARGET_TIMEOUT)
210 LOG_ERROR("loader not responding");
211 free(dcc_buffer);
212 return retval;
213 }
214
215 /* receive response */
216 if ((retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
217 {
218 free(dcc_buffer);
219 return retval;
220 }
221
222 if (dcc_buffer[0] != OCL_CMD_DONE)
223 {
224 LOG_ERROR("loader response to OCL_FLASH_BLOCK 0x%08" PRIx32 "", dcc_buffer[0]);
225 free(dcc_buffer);
226 return ERROR_FLASH_OPERATION_FAILED;
227 }
228
229 count -= runlen;
230 offset += runlen;
231 }
232
233 free(dcc_buffer);
234 return ERROR_OK;
235 }
236
237 static int ocl_probe(struct flash_bank *bank)
238 {
239 struct ocl_priv *ocl = bank->driver_priv;
240 int retval;
241 uint32_t dcc_buffer[1];
242 int sectsize;
243 int i;
244
245 /* purge pending data in DCC */
246 embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
247
248 dcc_buffer[0] = OCL_PROBE;
249 if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
250 return retval;
251
252 /* wait for response, fixed timeout of 1 s */
253 if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
254 {
255 if (retval == ERROR_TARGET_TIMEOUT)
256 LOG_ERROR("loader not responding");
257 return retval;
258 }
259
260 /* receive response */
261 if ((retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
262 return retval;
263
264 if (dcc_buffer[0] != OCL_CMD_DONE)
265 {
266 LOG_ERROR("loader response to OCL_PROBE 0x%08" PRIx32 "", dcc_buffer[0]);
267 return ERROR_FLASH_OPERATION_FAILED;
268 }
269
270 /* receive and fill in parameters, detection of loader is important, receive it one by one */
271 if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
272 || (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
273 return retval;
274 bank->base = dcc_buffer[0];
275
276 if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
277 || (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
278 return retval;
279 bank->size = dcc_buffer[0];
280
281 if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
282 || (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
283 return retval;
284 bank->num_sectors = dcc_buffer[0];
285
286 if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
287 || (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
288 return retval;
289 ocl->buflen = dcc_buffer[0] & 0xffff;
290 ocl->bufalign = dcc_buffer[0] >> 16;
291
292 bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector)*bank->num_sectors);
293 if (bank->num_sectors == 0)
294 {
295 LOG_ERROR("number of sectors shall be non zero value");
296 return ERROR_FLASH_BANK_INVALID;
297 }
298 if (bank->size % bank->num_sectors) {
299 LOG_ERROR("bank size not divisible by number of sectors");
300 return ERROR_FLASH_BANK_INVALID;
301 }
302 sectsize = bank->size / bank->num_sectors;
303 for (i = 0; i < bank->num_sectors; i++)
304 {
305 bank->sectors[i].offset = i * sectsize;
306 bank->sectors[i].size = sectsize;
307 bank->sectors[i].is_erased = -1;
308 bank->sectors[i].is_protected = -1;
309 }
310
311 if (ocl->bufalign == 0)
312 ocl->bufalign = 1;
313
314 if (ocl->buflen == 0)
315 {
316 LOG_ERROR("buflen shall be non zero value");
317 return ERROR_FLASH_BANK_INVALID;
318 }
319
320 if ((ocl->bufalign > ocl->buflen) || (ocl->buflen % ocl->bufalign))
321 {
322 LOG_ERROR("buflen is not multiple of bufalign");
323 return ERROR_FLASH_BANK_INVALID;
324 }
325
326 if (ocl->buflen % 4)
327 {
328 LOG_ERROR("buflen shall be divisible by 4");
329 return ERROR_FLASH_BANK_INVALID;
330 }
331
332 return ERROR_OK;
333 }
334
335 static int ocl_info(struct flash_bank *bank, char *buf, int buf_size)
336 {
337 return ERROR_OK;
338 }
339
340 static int ocl_auto_probe(struct flash_bank *bank)
341 {
342 struct ocl_priv *ocl = bank->driver_priv;
343
344 if (ocl->buflen == 0 || ocl->bufalign == 0)
345 return ERROR_FLASH_BANK_NOT_PROBED;
346
347 return ERROR_OK;
348 }
349
350 struct flash_driver ocl_flash = {
351 .name = "ocl",
352 .flash_bank_command = &ocl_flash_bank_command,
353 .erase = &ocl_erase,
354 .protect = &ocl_protect,
355 .write = &ocl_write,
356 .probe = &ocl_probe,
357 .erase_check = &ocl_erase_check,
358 .protect_check = &ocl_protect_check,
359 .info = &ocl_info,
360 .auto_probe = &ocl_auto_probe,
361 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)