str7x.c 22.9 KB
Newer Older
oharboe's avatar
oharboe committed
1
2
3
4
/***************************************************************************
 *   Copyright (C) 2005 by Dominic Rath                                    *
 *   Dominic.Rath@gmx.de                                                   *
 *                                                                         *
5
6
7
 *   Copyright (C) 2008 by Spencer Oliver                                  *
 *   spen@spen-soft.co.uk                                                  *
 *                                                                         *
Øyvind Harboe's avatar
Øyvind Harboe committed
8
9
10
 *   Copyright (C) 2010 Øyvind Harboe                                      *
 *   oyvind.harboe@zylin.com                                               *
 *                                                                         *
oharboe's avatar
oharboe committed
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

Zachary T Welch's avatar
Zachary T Welch committed
30
#include "imp.h"
31
#include <target/arm.h>
32
#include <helper/binarybuffer.h>
33
#include <target/algorithm.h>
oharboe's avatar
oharboe committed
34
35


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*  Flash registers */

#define FLASH_CR0		0x00000000
#define FLASH_CR1		0x00000004
#define FLASH_DR0		0x00000008
#define FLASH_DR1		0x0000000C
#define FLASH_AR		0x00000010
#define FLASH_ER		0x00000014
#define FLASH_NVWPAR	0x0000DFB0
#define FLASH_NVAPR0	0x0000DFB8
#define FLASH_NVAPR1	0x0000DFBC

/* FLASH_CR0 register bits */

#define FLASH_WMS		0x80000000
#define FLASH_SUSP		0x40000000
#define FLASH_WPG		0x20000000
#define FLASH_DWPG		0x10000000
#define FLASH_SER		0x08000000
#define FLASH_SPR		0x01000000
#define FLASH_BER		0x04000000
#define FLASH_MER		0x02000000
#define FLASH_LOCK		0x00000010
#define FLASH_BSYA1		0x00000004
#define FLASH_BSYA0		0x00000002

/* FLASH_CR1 register bits */

#define FLASH_B1S		0x02000000
#define FLASH_B0S		0x01000000
#define FLASH_B1F1		0x00020000
#define FLASH_B1F0		0x00010000
#define FLASH_B0F7		0x00000080
#define FLASH_B0F6		0x00000040
#define FLASH_B0F5		0x00000020
#define FLASH_B0F4		0x00000010
#define FLASH_B0F3		0x00000008
#define FLASH_B0F2		0x00000004
#define FLASH_B0F1		0x00000002
#define FLASH_B0F0		0x00000001

/* FLASH_ER register bits */

#define FLASH_WPF		0x00000100
#define FLASH_RESER		0x00000080
#define FLASH_SEQER		0x00000040
#define FLASH_10ER		0x00000008
#define FLASH_PGER		0x00000004
#define FLASH_ERER		0x00000002
#define FLASH_ERR		0x00000001


struct str7x_flash_bank
{
	uint32_t *sector_bits;
	uint32_t disable_bit;
	uint32_t busy_bits;
	uint32_t register_base;
	struct working_area *write_algorithm;
};

struct str7x_mem_layout {
	uint32_t sector_start;
	uint32_t sector_size;
	uint32_t sector_bit;
};

enum str7x_status_codes
{
	STR7X_CMD_SUCCESS = 0,
	STR7X_INVALID_COMMAND = 1,
	STR7X_SRC_ADDR_ERROR = 2,
	STR7X_DST_ADDR_ERROR = 3,
	STR7X_SRC_ADDR_NOT_MAPPED = 4,
	STR7X_DST_ADDR_NOT_MAPPED = 5,
	STR7X_COUNT_ERROR = 6,
	STR7X_INVALID_SECTOR = 7,
	STR7X_SECTOR_NOT_BLANK = 8,
	STR7X_SECTOR_NOT_PREPARED = 9,
	STR7X_COMPARE_ERROR = 10,
	STR7X_BUSY = 11
};

119
static struct str7x_mem_layout mem_layout_str7bank0[] = {
oharboe's avatar
oharboe committed
120
121
122
123
124
125
126
	{0x00000000, 0x02000, 0x01},
	{0x00002000, 0x02000, 0x02},
	{0x00004000, 0x02000, 0x04},
	{0x00006000, 0x02000, 0x08},
	{0x00008000, 0x08000, 0x10},
	{0x00010000, 0x10000, 0x20},
	{0x00020000, 0x10000, 0x40},
ntfreak's avatar
ntfreak committed
127
128
129
	{0x00030000, 0x10000, 0x80}
};

130
static struct str7x_mem_layout mem_layout_str7bank1[] = {
ntfreak's avatar
ntfreak committed
131
132
	{0x00000000, 0x02000, 0x10000},
	{0x00002000, 0x02000, 0x20000}
oharboe's avatar
oharboe committed
133
134
};

135
static int str7x_get_flash_adr(struct flash_bank *bank, uint32_t reg)
oharboe's avatar
oharboe committed
136
{
137
	struct str7x_flash_bank *str7x_info = bank->driver_priv;
ntfreak's avatar
ntfreak committed
138
	return (str7x_info->register_base | reg);
oharboe's avatar
oharboe committed
139
140
}

141
static int str7x_build_block_list(struct flash_bank *bank)
oharboe's avatar
oharboe committed
142
{
143
	struct str7x_flash_bank *str7x_info = bank->driver_priv;
oharboe's avatar
oharboe committed
144
145

	int i;
ntfreak's avatar
ntfreak committed
146
147
	int num_sectors;
	int b0_sectors = 0, b1_sectors = 0;
148

oharboe's avatar
oharboe committed
149
150
151
	switch (bank->size)
	{
		case 16 * 1024:
ntfreak's avatar
ntfreak committed
152
			b1_sectors = 2;
oharboe's avatar
oharboe committed
153
154
155
156
157
158
159
160
161
162
163
			break;
		case 64 * 1024:
			b0_sectors = 5;
			break;
		case 128 * 1024:
			b0_sectors = 6;
			break;
		case 256 * 1024:
			b0_sectors = 8;
			break;
		default:
164
			LOG_ERROR("BUG: unknown bank->size encountered");
oharboe's avatar
oharboe committed
165
166
			exit(-1);
	}
167

oharboe's avatar
oharboe committed
168
	num_sectors = b0_sectors + b1_sectors;
169

oharboe's avatar
oharboe committed
170
	bank->num_sectors = num_sectors;
171
	bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
172
	str7x_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors);
173

oharboe's avatar
oharboe committed
174
	num_sectors = 0;
175

oharboe's avatar
oharboe committed
176
177
	for (i = 0; i < b0_sectors; i++)
	{
ntfreak's avatar
ntfreak committed
178
179
		bank->sectors[num_sectors].offset = mem_layout_str7bank0[i].sector_start;
		bank->sectors[num_sectors].size = mem_layout_str7bank0[i].sector_size;
oharboe's avatar
oharboe committed
180
		bank->sectors[num_sectors].is_erased = -1;
181
182
183
184
		/* the reset_init handler marks all the sectors unprotected,
		 * matching hardware after reset; keep the driver in sync
		 */
		bank->sectors[num_sectors].is_protected = 0;
ntfreak's avatar
ntfreak committed
185
		str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank0[i].sector_bit;
oharboe's avatar
oharboe committed
186
	}
187

ntfreak's avatar
ntfreak committed
188
	for (i = 0; i < b1_sectors; i++)
oharboe's avatar
oharboe committed
189
	{
ntfreak's avatar
ntfreak committed
190
191
192
		bank->sectors[num_sectors].offset = mem_layout_str7bank1[i].sector_start;
		bank->sectors[num_sectors].size = mem_layout_str7bank1[i].sector_size;
		bank->sectors[num_sectors].is_erased = -1;
193
194
195
196
		/* the reset_init handler marks all the sectors unprotected,
		 * matching hardware after reset; keep the driver in sync
		 */
		bank->sectors[num_sectors].is_protected = 0;
ntfreak's avatar
ntfreak committed
197
		str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank1[i].sector_bit;
oharboe's avatar
oharboe committed
198
	}
199

oharboe's avatar
oharboe committed
200
201
202
203
204
	return ERROR_OK;
}

/* flash bank str7x <base> <size> 0 0 <target#> <str71_variant>
 */
205
FLASH_BANK_COMMAND_HANDLER(str7x_flash_bank_command)
oharboe's avatar
oharboe committed
206
{
207
	struct str7x_flash_bank *str7x_info;
208

209
	if (CMD_ARGC < 7)
oharboe's avatar
oharboe committed
210
	{
Mathias K's avatar
Mathias K committed
211
		return ERROR_COMMAND_SYNTAX_ERROR;
oharboe's avatar
oharboe committed
212
	}
213

214
	str7x_info = malloc(sizeof(struct str7x_flash_bank));
oharboe's avatar
oharboe committed
215
	bank->driver_priv = str7x_info;
216

oharboe's avatar
oharboe committed
217
	/* set default bits for str71x flash */
zwelch's avatar
zwelch committed
218
	str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA1 | FLASH_BSYA0);
zwelch's avatar
zwelch committed
219
	str7x_info->disable_bit = (1 << 1);
220

221
	if (strcmp(CMD_ARGV[6], "STR71x") == 0)
oharboe's avatar
oharboe committed
222
	{
ntfreak's avatar
ntfreak committed
223
		str7x_info->register_base = 0x40100000;
oharboe's avatar
oharboe committed
224
	}
225
	else if (strcmp(CMD_ARGV[6], "STR73x") == 0)
oharboe's avatar
oharboe committed
226
	{
ntfreak's avatar
ntfreak committed
227
		str7x_info->register_base = 0x80100000;
zwelch's avatar
zwelch committed
228
		str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA0);
oharboe's avatar
oharboe committed
229
	}
230
	else if (strcmp(CMD_ARGV[6], "STR75x") == 0)
oharboe's avatar
oharboe committed
231
	{
ntfreak's avatar
ntfreak committed
232
		str7x_info->register_base = 0x20100000;
zwelch's avatar
zwelch committed
233
		str7x_info->disable_bit = (1 << 0);
oharboe's avatar
oharboe committed
234
235
236
	}
	else
	{
237
		LOG_ERROR("unknown STR7x variant: '%s'", CMD_ARGV[6]);
oharboe's avatar
oharboe committed
238
239
240
241
242
		free(str7x_info);
		return ERROR_FLASH_BANK_INVALID;
	}

	str7x_build_block_list(bank);
243

oharboe's avatar
oharboe committed
244
	str7x_info->write_algorithm = NULL;
245

oharboe's avatar
oharboe committed
246
247
248
	return ERROR_OK;
}

Øyvind Harboe's avatar
Øyvind Harboe committed
249
250
251
252
253
254
255
256
257
258
259
/* wait for flash to become idle or report errors.

   FIX!!! what's the maximum timeout??? The documentation doesn't
   state any maximum time.... by inspection it seems > 1000ms is to be
   expected.

   10000ms is long enough that it should cover anything, yet not
   quite be equivalent to an infinite loop.

 */
static int str7x_waitbusy(struct flash_bank *bank)
oharboe's avatar
oharboe committed
260
{
Øyvind Harboe's avatar
Øyvind Harboe committed
261
262
	int err;
	int i;
Zachary T Welch's avatar
Zachary T Welch committed
263
	struct target *target = bank->target;
Øyvind Harboe's avatar
Øyvind Harboe committed
264
	struct str7x_flash_bank *str7x_info = bank->driver_priv;
oharboe's avatar
oharboe committed
265

Øyvind Harboe's avatar
Øyvind Harboe committed
266
267
268
269
270
271
	for (i = 0 ; i < 10000; i++)
	{
		uint32_t retval;
		err = target_read_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), &retval);
		if (err != ERROR_OK)
			return err;
oharboe's avatar
oharboe committed
272

Øyvind Harboe's avatar
Øyvind Harboe committed
273
274
275
276
277
278
279
		if ((retval & str7x_info->busy_bits) == 0)
			return ERROR_OK;

		alive_sleep(1);
	}
	LOG_ERROR("Timed out waiting for str7x flash");
	return ERROR_FAIL;
oharboe's avatar
oharboe committed
280
281
}

Øyvind Harboe's avatar
Øyvind Harboe committed
282
283

static int str7x_result(struct flash_bank *bank)
oharboe's avatar
oharboe committed
284
{
Zachary T Welch's avatar
Zachary T Welch committed
285
	struct target *target = bank->target;
Øyvind Harboe's avatar
Øyvind Harboe committed
286
	uint32_t flash_flags;
oharboe's avatar
oharboe committed
287

Øyvind Harboe's avatar
Øyvind Harboe committed
288
289
290
291
	int retval;
	retval = target_read_u32(target, str7x_get_flash_adr(bank, FLASH_ER), &flash_flags);
	if (retval != ERROR_OK)
		return retval;
Øyvind Harboe's avatar
Øyvind Harboe committed
292

Øyvind Harboe's avatar
Øyvind Harboe committed
293
	if (flash_flags & FLASH_WPF)
Øyvind Harboe's avatar
Øyvind Harboe committed
294
295
	{
		LOG_ERROR("str7x hw write protection set");
Øyvind Harboe's avatar
Øyvind Harboe committed
296
		retval = ERROR_FAIL;
Øyvind Harboe's avatar
Øyvind Harboe committed
297
	}
Øyvind Harboe's avatar
Øyvind Harboe committed
298
	if (flash_flags & FLASH_RESER)
Øyvind Harboe's avatar
Øyvind Harboe committed
299
300
	{
		LOG_ERROR("str7x suspended program erase not resumed");
Øyvind Harboe's avatar
Øyvind Harboe committed
301
		retval = ERROR_FAIL;
Øyvind Harboe's avatar
Øyvind Harboe committed
302
	}
Øyvind Harboe's avatar
Øyvind Harboe committed
303
	if (flash_flags & FLASH_10ER)
Øyvind Harboe's avatar
Øyvind Harboe committed
304
305
	{
		LOG_ERROR("str7x trying to set bit to 1 when it is already 0");
Øyvind Harboe's avatar
Øyvind Harboe committed
306
		retval = ERROR_FAIL;
Øyvind Harboe's avatar
Øyvind Harboe committed
307
	}
Øyvind Harboe's avatar
Øyvind Harboe committed
308
	if (flash_flags & FLASH_PGER)
Øyvind Harboe's avatar
Øyvind Harboe committed
309
310
	{
		LOG_ERROR("str7x program error");
Øyvind Harboe's avatar
Øyvind Harboe committed
311
		retval = ERROR_FAIL;
Øyvind Harboe's avatar
Øyvind Harboe committed
312
	}
Øyvind Harboe's avatar
Øyvind Harboe committed
313
	if (flash_flags & FLASH_ERER)
Øyvind Harboe's avatar
Øyvind Harboe committed
314
315
	{
		LOG_ERROR("str7x erase error");
Øyvind Harboe's avatar
Øyvind Harboe committed
316
		retval = ERROR_FAIL;
Øyvind Harboe's avatar
Øyvind Harboe committed
317
	}
Øyvind Harboe's avatar
Øyvind Harboe committed
318
	if (retval == ERROR_OK)
Øyvind Harboe's avatar
Øyvind Harboe committed
319
	{
Øyvind Harboe's avatar
Øyvind Harboe committed
320
		if (flash_flags & FLASH_ERR)
Øyvind Harboe's avatar
Øyvind Harboe committed
321
322
323
		{
			/* this should always be set if one of the others are set... */
			LOG_ERROR("str7x write operation failed / bad setup");
Øyvind Harboe's avatar
Øyvind Harboe committed
324
			retval = ERROR_FAIL;
Øyvind Harboe's avatar
Øyvind Harboe committed
325
326
		}
	}
327

oharboe's avatar
oharboe committed
328
329
330
	return retval;
}

331
static int str7x_protect_check(struct flash_bank *bank)
oharboe's avatar
oharboe committed
332
{
333
	struct str7x_flash_bank *str7x_info = bank->driver_priv;
Zachary T Welch's avatar
Zachary T Welch committed
334
	struct target *target = bank->target;
335

oharboe's avatar
oharboe committed
336
	int i;
Øyvind Harboe's avatar
Øyvind Harboe committed
337
	uint32_t flash_flags;
oharboe's avatar
oharboe committed
338
339
340

	if (bank->target->state != TARGET_HALTED)
	{
oharboe's avatar
oharboe committed
341
		LOG_ERROR("Target not halted");
oharboe's avatar
oharboe committed
342
343
344
		return ERROR_TARGET_NOT_HALTED;
	}

Øyvind Harboe's avatar
Øyvind Harboe committed
345
346
347
348
	int retval;
	retval = target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVWPAR), &flash_flags);
	if (retval != ERROR_OK)
		return retval;
oharboe's avatar
oharboe committed
349
350
351

	for (i = 0; i < bank->num_sectors; i++)
	{
Øyvind Harboe's avatar
Øyvind Harboe committed
352
		if (flash_flags & str7x_info->sector_bits[i])
oharboe's avatar
oharboe committed
353
354
355
356
357
358
359
360
			bank->sectors[i].is_protected = 0;
		else
			bank->sectors[i].is_protected = 1;
	}

	return ERROR_OK;
}

361
static int str7x_erase(struct flash_bank *bank, int first, int last)
oharboe's avatar
oharboe committed
362
{
363
	struct str7x_flash_bank *str7x_info = bank->driver_priv;
Zachary T Welch's avatar
Zachary T Welch committed
364
	struct target *target = bank->target;
365

oharboe's avatar
oharboe committed
366
	int i;
367
368
	uint32_t cmd;
	uint32_t sectors = 0;
Øyvind Harboe's avatar
Øyvind Harboe committed
369
	int err;
370

371
372
	if (bank->target->state != TARGET_HALTED)
	{
oharboe's avatar
oharboe committed
373
		LOG_ERROR("Target not halted");
374
375
376
		return ERROR_TARGET_NOT_HALTED;
	}

oharboe's avatar
oharboe committed
377
378
	for (i = first; i <= last; i++)
	{
ntfreak's avatar
ntfreak committed
379
		sectors |= str7x_info->sector_bits[i];
oharboe's avatar
oharboe committed
380
	}
381

duane's avatar
duane committed
382
	LOG_DEBUG("sectors: 0x%" PRIx32 "", sectors);
383
384

	/* clear FLASH_ER register */
Øyvind Harboe's avatar
Øyvind Harboe committed
385
386
387
	err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
	if (err != ERROR_OK)
		return err;
388

ntfreak's avatar
ntfreak committed
389
	cmd = FLASH_SER;
Øyvind Harboe's avatar
Øyvind Harboe committed
390
391
392
	err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
	if (err != ERROR_OK)
		return err;
393

ntfreak's avatar
ntfreak committed
394
	cmd = sectors;
Øyvind Harboe's avatar
Øyvind Harboe committed
395
396
397
	err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR1), cmd);
	if (err != ERROR_OK)
		return err;
398

zwelch's avatar
zwelch committed
399
	cmd = FLASH_SER | FLASH_WMS;
Øyvind Harboe's avatar
Øyvind Harboe committed
400
401
402
	err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
	if (err != ERROR_OK)
		return err;
403

Øyvind Harboe's avatar
Øyvind Harboe committed
404
405
406
	err = str7x_waitbusy(bank);
	if (err != ERROR_OK)
		return err;
407

Øyvind Harboe's avatar
Øyvind Harboe committed
408
409
410
	err = str7x_result(bank);
	if (err != ERROR_OK)
		return err;
411

oharboe's avatar
oharboe committed
412
413
414
415
416
417
	for (i = first; i <= last; i++)
		bank->sectors[i].is_erased = 1;

	return ERROR_OK;
}

418
static int str7x_protect(struct flash_bank *bank, int set, int first, int last)
oharboe's avatar
oharboe committed
419
{
420
	struct str7x_flash_bank *str7x_info = bank->driver_priv;
Zachary T Welch's avatar
Zachary T Welch committed
421
	struct target *target = bank->target;
oharboe's avatar
oharboe committed
422
	int i;
423
424
	uint32_t cmd;
	uint32_t protect_blocks;
425

oharboe's avatar
oharboe committed
426
427
	if (bank->target->state != TARGET_HALTED)
	{
oharboe's avatar
oharboe committed
428
		LOG_ERROR("Target not halted");
oharboe's avatar
oharboe committed
429
430
		return ERROR_TARGET_NOT_HALTED;
	}
431

oharboe's avatar
oharboe committed
432
433
434
435
436
437
438
	protect_blocks = 0xFFFFFFFF;

	if (set)
	{
		for (i = first; i <= last; i++)
			protect_blocks &= ~(str7x_info->sector_bits[i]);
	}
439
440

	/* clear FLASH_ER register */
Øyvind Harboe's avatar
Øyvind Harboe committed
441
442
443
444
	int err;
	err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
	if (err != ERROR_OK)
		return err;
oharboe's avatar
oharboe committed
445
446

	cmd = FLASH_SPR;
Øyvind Harboe's avatar
Øyvind Harboe committed
447
448
449
	err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
	if (err != ERROR_OK)
		return err;
450

oharboe's avatar
oharboe committed
451
	cmd = str7x_get_flash_adr(bank, FLASH_NVWPAR);
Øyvind Harboe's avatar
Øyvind Harboe committed
452
453
454
	err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), cmd);
	if (err != ERROR_OK)
		return err;
455

oharboe's avatar
oharboe committed
456
	cmd = protect_blocks;
Øyvind Harboe's avatar
Øyvind Harboe committed
457
458
459
	err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), cmd);
	if (err != ERROR_OK)
		return err;
460

zwelch's avatar
zwelch committed
461
	cmd = FLASH_SPR | FLASH_WMS;
Øyvind Harboe's avatar
Øyvind Harboe committed
462
463
464
	err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
	if (err != ERROR_OK)
		return err;
465

Øyvind Harboe's avatar
Øyvind Harboe committed
466
467
468
	err = str7x_waitbusy(bank);
	if (err != ERROR_OK)
		return err;
469

Øyvind Harboe's avatar
Øyvind Harboe committed
470
471
472
	err = str7x_result(bank);
	if (err != ERROR_OK)
		return err;
oharboe's avatar
oharboe committed
473
474
475
476

	return ERROR_OK;
}

477
static int str7x_write_block(struct flash_bank *bank, uint8_t *buffer,
Spencer Oliver's avatar
Spencer Oliver committed
478
		uint32_t offset, uint32_t count)
oharboe's avatar
oharboe committed
479
{
480
	struct str7x_flash_bank *str7x_info = bank->driver_priv;
Zachary T Welch's avatar
Zachary T Welch committed
481
	struct target *target = bank->target;
Spencer Oliver's avatar
Spencer Oliver committed
482
	uint32_t buffer_size = 32768;
483
	struct working_area *source;
484
	uint32_t address = bank->base + offset;
485
	struct reg_param reg_params[6];
486
	struct arm_algorithm armv4_5_info;
oharboe's avatar
oharboe committed
487
	int retval = ERROR_OK;
488

489
490
	/* see contib/loaders/flash/str7x.s for src */

Spencer Oliver's avatar
Spencer Oliver committed
491
	static const uint32_t str7x_flash_write_code[] = {
oharboe's avatar
oharboe committed
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
					/* write:				*/
		0xe3a04201, /*	mov r4, #0x10000000	*/
		0xe5824000, /*	str r4, [r2, #0x0]	*/
		0xe5821010, /*	str r1, [r2, #0x10]	*/
		0xe4904004, /*	ldr r4, [r0], #4	*/
		0xe5824008, /*	str r4, [r2, #0x8]	*/
		0xe4904004, /*	ldr r4, [r0], #4	*/
		0xe582400c, /*	str r4, [r2, #0xc]	*/
		0xe3a04209, /*	mov r4, #0x90000000	*/
		0xe5824000, /*	str r4, [r2, #0x0]	*/
		            /* busy:				*/
		0xe5924000, /*	ldr r4, [r2, #0x0]	*/
		0xe1140005,	/*	tst r4, r5			*/
		0x1afffffc, /*	bne busy			*/
		0xe5924014, /*	ldr r4, [r2, #0x14]	*/
		0xe31400ff, /*	tst r4, #0xff		*/
		0x03140c01, /*	tsteq r4, #0x100	*/
		0x1a000002, /*	bne exit			*/
		0xe2811008, /*	add r1, r1, #0x8	*/
		0xe2533001, /*	subs r3, r3, #1		*/
		0x1affffec, /*	bne write			*/
					/* exit:				*/
		0xeafffffe, /*	b exit				*/
	};
516

oharboe's avatar
oharboe committed
517
	/* flash write code */
518
	if (target_alloc_working_area_try(target, sizeof(str7x_flash_write_code),
Spencer Oliver's avatar
Spencer Oliver committed
519
			&str7x_info->write_algorithm) != ERROR_OK)
oharboe's avatar
oharboe committed
520
521
522
	{
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	};
523

Spencer Oliver's avatar
Spencer Oliver committed
524
525
526
	target_write_buffer(target, str7x_info->write_algorithm->address,
			sizeof(str7x_flash_write_code),
			(uint8_t*)str7x_flash_write_code);
oharboe's avatar
oharboe committed
527
528

	/* memory buffer */
529
	while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
oharboe's avatar
oharboe committed
530
531
532
533
	{
		buffer_size /= 2;
		if (buffer_size <= 256)
		{
Spencer Oliver's avatar
Spencer Oliver committed
534
535
			/* if we already allocated the writing code, but failed to get a
			 * buffer, free the algorithm */
oharboe's avatar
oharboe committed
536
537
			if (str7x_info->write_algorithm)
				target_free_working_area(target, str7x_info->write_algorithm);
538

539
			LOG_WARNING("no large enough working area available, can't do block memory writes");
oharboe's avatar
oharboe committed
540
541
542
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
	}
543

544
	armv4_5_info.common_magic = ARM_COMMON_MAGIC;
545
	armv4_5_info.core_mode = ARM_MODE_SVC;
546
	armv4_5_info.core_state = ARM_STATE_ARM;
547

oharboe's avatar
oharboe committed
548
549
550
551
552
553
	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
	init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
	init_reg_param(&reg_params[4], "r4", 32, PARAM_IN);
	init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);
554

oharboe's avatar
oharboe committed
555
556
	while (count > 0)
	{
557
		uint32_t thisrun_count = (count > (buffer_size / 8)) ? (buffer_size / 8) : count;
558

oharboe's avatar
oharboe committed
559
		target_write_buffer(target, source->address, thisrun_count * 8, buffer);
560

oharboe's avatar
oharboe committed
561
562
563
564
565
		buf_set_u32(reg_params[0].value, 0, 32, source->address);
		buf_set_u32(reg_params[1].value, 0, 32, address);
		buf_set_u32(reg_params[2].value, 0, 32, str7x_get_flash_adr(bank, FLASH_CR0));
		buf_set_u32(reg_params[3].value, 0, 32, thisrun_count);
		buf_set_u32(reg_params[5].value, 0, 32, str7x_info->busy_bits);
566

Spencer Oliver's avatar
Spencer Oliver committed
567
568
569
570
		if ((retval = target_run_algorithm(target, 0, NULL, 6, reg_params,
				str7x_info->write_algorithm->address,
				str7x_info->write_algorithm->address + (sizeof(str7x_flash_write_code) - 4),
				10000, &armv4_5_info)) != ERROR_OK)
oharboe's avatar
oharboe committed
571
572
573
		{
			break;
		}
574

oharboe's avatar
oharboe committed
575
576
		if (buf_get_u32(reg_params[4].value, 0, 32) != 0x00)
		{
Øyvind Harboe's avatar
Øyvind Harboe committed
577
			retval = str7x_result(bank);
oharboe's avatar
oharboe committed
578
579
			break;
		}
580

oharboe's avatar
oharboe committed
581
582
583
584
		buffer += thisrun_count * 8;
		address += thisrun_count * 8;
		count -= thisrun_count;
	}
585

oharboe's avatar
oharboe committed
586
587
	target_free_working_area(target, source);
	target_free_working_area(target, str7x_info->write_algorithm);
588

oharboe's avatar
oharboe committed
589
590
591
592
593
594
	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);
	destroy_reg_param(&reg_params[3]);
	destroy_reg_param(&reg_params[4]);
	destroy_reg_param(&reg_params[5]);
595

oharboe's avatar
oharboe committed
596
597
598
	return retval;
}

Spencer Oliver's avatar
Spencer Oliver committed
599
600
static int str7x_write(struct flash_bank *bank, uint8_t *buffer,
		uint32_t offset, uint32_t count)
oharboe's avatar
oharboe committed
601
{
Zachary T Welch's avatar
Zachary T Welch committed
602
	struct target *target = bank->target;
603
604
605
606
607
	uint32_t dwords_remaining = (count / 8);
	uint32_t bytes_remaining = (count & 0x00000007);
	uint32_t address = bank->base + offset;
	uint32_t bytes_written = 0;
	uint32_t cmd;
608
	int retval;
609
	uint32_t check_address = offset;
oharboe's avatar
oharboe committed
610
	int i;
611

612
613
	if (bank->target->state != TARGET_HALTED)
	{
oharboe's avatar
oharboe committed
614
		LOG_ERROR("Target not halted");
615
616
617
		return ERROR_TARGET_NOT_HALTED;
	}

oharboe's avatar
oharboe committed
618
619
	if (offset & 0x7)
	{
duane's avatar
duane committed
620
		LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment", offset);
oharboe's avatar
oharboe committed
621
622
		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
	}
623

oharboe's avatar
oharboe committed
624
625
	for (i = 0; i < bank->num_sectors; i++)
	{
626
627
		uint32_t sec_start = bank->sectors[i].offset;
		uint32_t sec_end = sec_start + bank->sectors[i].size;
628

oharboe's avatar
oharboe committed
629
630
631
632
633
634
635
636
637
638
		/* check if destination falls within the current sector */
		if ((check_address >= sec_start) && (check_address < sec_end))
		{
			/* check if destination ends in the current sector */
			if (offset + count < sec_end)
				check_address = offset + count;
			else
				check_address = sec_end;
		}
	}
639

oharboe's avatar
oharboe committed
640
641
	if (check_address != offset + count)
		return ERROR_FLASH_DST_OUT_OF_BANK;
642
643

	/* clear FLASH_ER register */
oharboe's avatar
oharboe committed
644
645
646
	target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);

	/* multiple dwords (8-byte) to be programmed? */
647
	if (dwords_remaining > 0)
oharboe's avatar
oharboe committed
648
649
	{
		/* try using a block write */
Spencer Oliver's avatar
Spencer Oliver committed
650
651
		if ((retval = str7x_write_block(bank, buffer, offset,
				dwords_remaining)) != ERROR_OK)
oharboe's avatar
oharboe committed
652
653
654
655
		{
			if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
			{
				/* if block write failed (no sufficient working area),
656
				 * we use normal (slow) single dword accesses */
657
				LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
Øyvind Harboe's avatar
Øyvind Harboe committed
658
			} else
Spencer Oliver's avatar
Spencer Oliver committed
659
660
661
			{
				return retval;
			}
oharboe's avatar
oharboe committed
662
663
664
665
666
667
668
669
670
671
672
		}
		else
		{
			buffer += dwords_remaining * 8;
			address += dwords_remaining * 8;
			dwords_remaining = 0;
		}
	}

	while (dwords_remaining > 0)
	{
673
		/* command */
oharboe's avatar
oharboe committed
674
675
		cmd = FLASH_DWPG;
		target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
676

677
		/* address */
oharboe's avatar
oharboe committed
678
		target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
679

680
		/* data word 1 */
Spencer Oliver's avatar
Spencer Oliver committed
681
682
		target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0),
				4, 1, buffer + bytes_written);
oharboe's avatar
oharboe committed
683
		bytes_written += 4;
684

685
		/* data word 2 */
Spencer Oliver's avatar
Spencer Oliver committed
686
687
		target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1),
				4, 1, buffer + bytes_written);
oharboe's avatar
oharboe committed
688
		bytes_written += 4;
689

oharboe's avatar
oharboe committed
690
691
692
		/* start programming cycle */
		cmd = FLASH_DWPG | FLASH_WMS;
		target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
693

Øyvind Harboe's avatar
Øyvind Harboe committed
694
695
696
697
		int err;
		err = str7x_waitbusy(bank);
		if (err != ERROR_OK)
			return err;
698

Øyvind Harboe's avatar
Øyvind Harboe committed
699
700
701
		err = str7x_result(bank);
		if (err != ERROR_OK)
			return err;
oharboe's avatar
oharboe committed
702
703
704
705

		dwords_remaining--;
		address += 8;
	}
706

oharboe's avatar
oharboe committed
707
708
	if (bytes_remaining)
	{
709
		uint8_t last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
710

711
712
		/* copy the last remaining bytes into the write buffer */
		memcpy(last_dword, buffer+bytes_written, bytes_remaining);
713

714
		/* command */
oharboe's avatar
oharboe committed
715
716
		cmd = FLASH_DWPG;
		target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
717

718
		/* address */
oharboe's avatar
oharboe committed
719
		target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
720

721
		/* data word 1 */
Spencer Oliver's avatar
Spencer Oliver committed
722
723
		target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0),
				4, 1, last_dword);
724

725
		/* data word 2 */
Spencer Oliver's avatar
Spencer Oliver committed
726
727
		target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1),
				4, 1, last_dword + 4);
728

oharboe's avatar
oharboe committed
729
730
731
		/* start programming cycle */
		cmd = FLASH_DWPG | FLASH_WMS;
		target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
732

Øyvind Harboe's avatar
Øyvind Harboe committed
733
734
735
736
		int err;
		err = str7x_waitbusy(bank);
		if (err != ERROR_OK)
			return err;
737

Øyvind Harboe's avatar
Øyvind Harboe committed
738
739
740
		err = str7x_result(bank);
		if (err != ERROR_OK)
			return err;
oharboe's avatar
oharboe committed
741
	}
742

oharboe's avatar
oharboe committed
743
744
745
	return ERROR_OK;
}

746
static int str7x_probe(struct flash_bank *bank)
oharboe's avatar
oharboe committed
747
748
749
750
{
	return ERROR_OK;
}

mifi's avatar
mifi committed
751
#if 0
752
COMMAND_HANDLER(str7x_handle_part_id_command)
oharboe's avatar
oharboe committed
753
754
755
{
	return ERROR_OK;
}
mifi's avatar
mifi committed
756
#endif
oharboe's avatar
oharboe committed
757

Øyvind Harboe's avatar
Øyvind Harboe committed
758
static int get_str7x_info(struct flash_bank *bank, char *buf, int buf_size)
oharboe's avatar
oharboe committed
759
{
760
	snprintf(buf, buf_size, "str7x flash driver info");
761
762
763
764
765
766
	/* STR7x flash doesn't support sector protection interrogation.
	 * FLASH_NVWPAR acts as a write only register; its read value
	 * doesn't reflect the actual protection state of the sectors.
	 */
	LOG_WARNING("STR7x flash lock information might not be correct "
			"due to hardware limitations.");
oharboe's avatar
oharboe committed
767
768
769
	return ERROR_OK;
}

770
COMMAND_HANDLER(str7x_handle_disable_jtag_command)
oharboe's avatar
oharboe committed
771
{
Zachary T Welch's avatar
Zachary T Welch committed
772
	struct target *target = NULL;
773
	struct str7x_flash_bank *str7x_info = NULL;
774

775
	uint32_t flash_cmd;
zwelch's avatar
zwelch committed
776
777
	uint16_t ProtectionLevel = 0;
	uint16_t ProtectionRegs;
778

779
	if (CMD_ARGC < 1)
oharboe's avatar
oharboe committed
780
	{
Mathias K's avatar
Mathias K committed
781
		return ERROR_COMMAND_SYNTAX_ERROR;
oharboe's avatar
oharboe committed
782
	}
783

784
	struct flash_bank *bank;
785
	int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
786
787
	if (ERROR_OK != retval)
		return retval;
788

oharboe's avatar
oharboe committed
789
	str7x_info = bank->driver_priv;
790

oharboe's avatar
oharboe committed
791
	target = bank->target;
792

oharboe's avatar
oharboe committed
793
794
	if (target->state != TARGET_HALTED)
	{
oharboe's avatar
oharboe committed
795
		LOG_ERROR("Target not halted");
oharboe's avatar
oharboe committed
796
797
		return ERROR_TARGET_NOT_HALTED;
	}
798

oharboe's avatar
oharboe committed
799
	/* first we get protection status */
800
801
	uint32_t reg;
	target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR0), &reg);
oharboe's avatar
oharboe committed
802

803
	if (!(reg & str7x_info->disable_bit))
oharboe's avatar
oharboe committed
804
805
806
	{
		ProtectionLevel = 1;
	}
807

808
809
	target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR1), &reg);
	ProtectionRegs = ~(reg >> 16);
oharboe's avatar
oharboe committed
810
811
812
813
814
815

	while (((ProtectionRegs) != 0) && (ProtectionLevel < 16))
	{
		ProtectionRegs >>= 1;
		ProtectionLevel++;
	}
816

oharboe's avatar
oharboe committed
817
818
819
820
821
822
823
824
825
826
827
828
829
830
	if (ProtectionLevel == 0)
	{
		flash_cmd = FLASH_SPR;
		target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
		target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFB8);
		target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), 0xFFFFFFFD);
		flash_cmd = FLASH_SPR | FLASH_WMS;
		target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
	}
	else
	{
		flash_cmd = FLASH_SPR;
		target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
		target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFBC);
Spencer Oliver's avatar
Spencer Oliver committed
831
832
		target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0),
				~(1 << (15 + ProtectionLevel)));
oharboe's avatar
oharboe committed
833
834
835
		flash_cmd = FLASH_SPR | FLASH_WMS;
		target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
	}
836

oharboe's avatar
oharboe committed
837
838
	return ERROR_OK;
}
839

840
841
842
static const struct command_registration str7x_exec_command_handlers[] = {
	{
		.name = "disable_jtag",
Mathias K's avatar
Mathias K committed
843
		.usage = "<bank>",
David Brownell's avatar
David Brownell committed
844
		.handler = str7x_handle_disable_jtag_command,
845
846
847
848
849
		.mode = COMMAND_EXEC,
		.help = "disable jtag access",
	},
	COMMAND_REGISTRATION_DONE
};
Spencer Oliver's avatar
Spencer Oliver committed
850

851
852
853
854
855
856
857
858
859
860
static const struct command_registration str7x_command_handlers[] = {
	{
		.name = "str7x",
		.mode = COMMAND_ANY,
		.help = "str7x flash command group",
		.chain = str7x_exec_command_handlers,
	},
	COMMAND_REGISTRATION_DONE
};

861
struct flash_driver str7x_flash = {
David Brownell's avatar
David Brownell committed
862
863
864
865
866
867
	.name = "str7x",
	.commands = str7x_command_handlers,
	.flash_bank_command = str7x_flash_bank_command,
	.erase = str7x_erase,
	.protect = str7x_protect,
	.write = str7x_write,
868
	.read = default_flash_read,
David Brownell's avatar
David Brownell committed
869
870
871
872
	.probe = str7x_probe,
	.auto_probe = str7x_probe,
	.erase_check = default_flash_blank_check,
	.protect_check = str7x_protect_check,
Øyvind Harboe's avatar
Øyvind Harboe committed
873
	.info = get_str7x_info,
David Brownell's avatar
David Brownell committed
874
};