str9x.c 17.6 KB
Newer Older
oharboe's avatar
oharboe committed
1
2
3
4
/***************************************************************************
 *   Copyright (C) 2005 by Dominic Rath                                    *
 *   Dominic.Rath@gmx.de                                                   *
 *                                                                         *
5
6
 *   Copyright (C) 2008 by Spencer Oliver                                  *
 *   spen@spen-soft.co.uk                                                  *
oharboe's avatar
oharboe committed
7
8
9
 *
 *   Copyright (C) 2008 by Oyvind Harboe                                   *
 *   oyvind.harboe@zylin.com                                               *
10
 *                                                                         *
oharboe's avatar
oharboe committed
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 *   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

#include "str9x.h"
#include "arm966e.h"


34
static uint32_t bank1start = 0x00080000;
oharboe's avatar
oharboe committed
35

mifi's avatar
mifi committed
36
static int str9x_build_block_list(struct flash_bank_s *bank)
oharboe's avatar
oharboe committed
37
{
38
	struct str9x_flash_bank *str9x_info = bank->driver_priv;
zwelch's avatar
zwelch committed
39

oharboe's avatar
oharboe committed
40
	int i;
ntfreak's avatar
ntfreak committed
41
	int num_sectors;
oharboe's avatar
oharboe committed
42
	int b0_sectors = 0, b1_sectors = 0;
43
	uint32_t offset = 0;
zwelch's avatar
zwelch committed
44

ntfreak's avatar
ntfreak committed
45
46
47
	/* set if we have large flash str9 */
	str9x_info->variant = 0;
	str9x_info->bank1 = 0;
zwelch's avatar
zwelch committed
48

oharboe's avatar
oharboe committed
49
50
51
52
53
54
55
56
	switch (bank->size)
	{
		case (256 * 1024):
			b0_sectors = 4;
			break;
		case (512 * 1024):
			b0_sectors = 8;
			break;
ntfreak's avatar
ntfreak committed
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
		case (1024 * 1024):
			bank1start = 0x00100000;
			str9x_info->variant = 1;
			b0_sectors = 16;
			break;
		case (2048 * 1024):
			bank1start = 0x00200000;
			str9x_info->variant = 1;
			b0_sectors = 32;
			break;
		case (128 * 1024):
			str9x_info->variant = 1;
			str9x_info->bank1 = 1;
			b1_sectors = 8;
			bank1start = bank->base;
			break;
oharboe's avatar
oharboe committed
73
		case (32 * 1024):
ntfreak's avatar
ntfreak committed
74
			str9x_info->bank1 = 1;
oharboe's avatar
oharboe committed
75
76
77
78
			b1_sectors = 4;
			bank1start = bank->base;
			break;
		default:
79
			LOG_ERROR("BUG: unknown bank->size encountered");
oharboe's avatar
oharboe committed
80
81
			exit(-1);
	}
zwelch's avatar
zwelch committed
82

oharboe's avatar
oharboe committed
83
	num_sectors = b0_sectors + b1_sectors;
zwelch's avatar
zwelch committed
84

oharboe's avatar
oharboe committed
85
	bank->num_sectors = num_sectors;
86
	bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
87
	str9x_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors);
zwelch's avatar
zwelch committed
88

oharboe's avatar
oharboe committed
89
	num_sectors = 0;
zwelch's avatar
zwelch committed
90

oharboe's avatar
oharboe committed
91
92
	for (i = 0; i < b0_sectors; i++)
	{
ntfreak's avatar
ntfreak committed
93
94
95
		bank->sectors[num_sectors].offset = offset;
		bank->sectors[num_sectors].size = 0x10000;
		offset += bank->sectors[i].size;
oharboe's avatar
oharboe committed
96
97
		bank->sectors[num_sectors].is_erased = -1;
		bank->sectors[num_sectors].is_protected = 1;
zwelch's avatar
zwelch committed
98
		str9x_info->sector_bits[num_sectors++] = (1 << i);
oharboe's avatar
oharboe committed
99
100
101
102
	}

	for (i = 0; i < b1_sectors; i++)
	{
ntfreak's avatar
ntfreak committed
103
104
105
		bank->sectors[num_sectors].offset = offset;
		bank->sectors[num_sectors].size = str9x_info->variant == 0 ? 0x2000 : 0x4000;
		offset += bank->sectors[i].size;
oharboe's avatar
oharboe committed
106
107
		bank->sectors[num_sectors].is_erased = -1;
		bank->sectors[num_sectors].is_protected = 1;
ntfreak's avatar
ntfreak committed
108
		if (str9x_info->variant)
zwelch's avatar
zwelch committed
109
			str9x_info->sector_bits[num_sectors++] = (1 << i);
ntfreak's avatar
ntfreak committed
110
		else
zwelch's avatar
zwelch committed
111
			str9x_info->sector_bits[num_sectors++] = (1 << (i + 8));
oharboe's avatar
oharboe committed
112
	}
zwelch's avatar
zwelch committed
113

oharboe's avatar
oharboe committed
114
115
116
117
118
	return ERROR_OK;
}

/* flash bank str9x <base> <size> 0 0 <target#>
 */
119
FLASH_BANK_COMMAND_HANDLER(str9x_flash_bank_command)
oharboe's avatar
oharboe committed
120
{
121
	struct str9x_flash_bank *str9x_info;
zwelch's avatar
zwelch committed
122

oharboe's avatar
oharboe committed
123
124
	if (argc < 6)
	{
125
		LOG_WARNING("incomplete flash_bank str9x configuration");
oharboe's avatar
oharboe committed
126
127
		return ERROR_FLASH_BANK_INVALID;
	}
zwelch's avatar
zwelch committed
128

129
	str9x_info = malloc(sizeof(struct str9x_flash_bank));
oharboe's avatar
oharboe committed
130
	bank->driver_priv = str9x_info;
zwelch's avatar
zwelch committed
131

oharboe's avatar
oharboe committed
132
	str9x_build_block_list(bank);
zwelch's avatar
zwelch committed
133

oharboe's avatar
oharboe committed
134
	str9x_info->write_algorithm = NULL;
zwelch's avatar
zwelch committed
135

oharboe's avatar
oharboe committed
136
137
138
	return ERROR_OK;
}

mifi's avatar
mifi committed
139
static int str9x_protect_check(struct flash_bank_s *bank)
oharboe's avatar
oharboe committed
140
{
oharboe's avatar
oharboe committed
141
	int retval;
142
	struct str9x_flash_bank *str9x_info = bank->driver_priv;
oharboe's avatar
oharboe committed
143
	target_t *target = bank->target;
zwelch's avatar
zwelch committed
144

oharboe's avatar
oharboe committed
145
	int i;
146
147
	uint32_t adr;
	uint32_t status = 0;
zwelch's avatar
zwelch committed
148
	uint16_t hstatus = 0;
oharboe's avatar
oharboe committed
149
150
151

	if (bank->target->state != TARGET_HALTED)
	{
oharboe's avatar
oharboe committed
152
		LOG_ERROR("Target not halted");
oharboe's avatar
oharboe committed
153
154
155
156
		return ERROR_TARGET_NOT_HALTED;
	}

	/* read level one protection */
zwelch's avatar
zwelch committed
157

ntfreak's avatar
ntfreak committed
158
159
160
161
162
	if (str9x_info->variant)
	{
		if (str9x_info->bank1)
		{
			adr = bank1start + 0x18;
zwelch's avatar
zwelch committed
163
			if ((retval = target_write_u16(target, adr, 0x90)) != ERROR_OK)
oharboe's avatar
oharboe committed
164
165
166
			{
				return retval;
			}
zwelch's avatar
zwelch committed
167
			if ((retval = target_read_u16(target, adr, &hstatus)) != ERROR_OK)
oharboe's avatar
oharboe committed
168
169
170
			{
				return retval;
			}
171
			status = hstatus;
ntfreak's avatar
ntfreak committed
172
173
174
175
		}
		else
		{
			adr = bank1start + 0x14;
zwelch's avatar
zwelch committed
176
			if ((retval = target_write_u16(target, adr, 0x90)) != ERROR_OK)
oharboe's avatar
oharboe committed
177
178
179
			{
				return retval;
			}
zwelch's avatar
zwelch committed
180
			if ((retval = target_read_u32(target, adr, &status)) != ERROR_OK)
oharboe's avatar
oharboe committed
181
182
183
			{
				return retval;
			}
ntfreak's avatar
ntfreak committed
184
185
186
187
188
		}
	}
	else
	{
		adr = bank1start + 0x10;
zwelch's avatar
zwelch committed
189
		if ((retval = target_write_u16(target, adr, 0x90)) != ERROR_OK)
oharboe's avatar
oharboe committed
190
191
192
		{
			return retval;
		}
zwelch's avatar
zwelch committed
193
		if ((retval = target_read_u16(target, adr, &hstatus)) != ERROR_OK)
oharboe's avatar
oharboe committed
194
195
196
		{
			return retval;
		}
197
		status = hstatus;
ntfreak's avatar
ntfreak committed
198
	}
zwelch's avatar
zwelch committed
199

200
	/* read array command */
zwelch's avatar
zwelch committed
201
	if ((retval = target_write_u16(target, adr, 0xFF)) != ERROR_OK)
oharboe's avatar
oharboe committed
202
203
204
	{
		return retval;
	}
zwelch's avatar
zwelch committed
205

oharboe's avatar
oharboe committed
206
207
208
209
210
211
212
	for (i = 0; i < bank->num_sectors; i++)
	{
		if (status & str9x_info->sector_bits[i])
			bank->sectors[i].is_protected = 1;
		else
			bank->sectors[i].is_protected = 0;
	}
zwelch's avatar
zwelch committed
213

oharboe's avatar
oharboe committed
214
215
216
	return ERROR_OK;
}

mifi's avatar
mifi committed
217
static int str9x_erase(struct flash_bank_s *bank, int first, int last)
oharboe's avatar
oharboe committed
218
219
220
{
	target_t *target = bank->target;
	int i;
221
	uint32_t adr;
222
223
	uint8_t status;
	uint8_t erase_cmd;
zwelch's avatar
zwelch committed
224

225
226
	if (bank->target->state != TARGET_HALTED)
	{
oharboe's avatar
oharboe committed
227
		LOG_ERROR("Target not halted");
228
229
230
		return ERROR_TARGET_NOT_HALTED;
	}

231
232
233
234
235
236
237
238
239
240
241
	/* Check if we erase whole bank */
	if ((first == 0) && (last == (bank->num_sectors - 1)))
	{
		/* Optimize to run erase bank command instead of sector */
		erase_cmd = 0x80;
	}
	else
	{
		/* Erase sector command */
		erase_cmd = 0x20;
	}
zwelch's avatar
zwelch committed
242

oharboe's avatar
oharboe committed
243
244
	for (i = first; i <= last; i++)
	{
245
		int retval;
oharboe's avatar
oharboe committed
246
		adr = bank->base + bank->sectors[i].offset;
zwelch's avatar
zwelch committed
247

248
		/* erase sectors */
zwelch's avatar
zwelch committed
249
		if ((retval = target_write_u16(target, adr, erase_cmd)) != ERROR_OK)
250
251
252
		{
			return retval;
		}
zwelch's avatar
zwelch committed
253
		if ((retval = target_write_u16(target, adr, 0xD0)) != ERROR_OK)
254
255
256
		{
			return retval;
		}
zwelch's avatar
zwelch committed
257

oharboe's avatar
oharboe committed
258
		/* get status */
zwelch's avatar
zwelch committed
259
		if ((retval = target_write_u16(target, adr, 0x70)) != ERROR_OK)
260
261
262
		{
			return retval;
		}
oharboe's avatar
oharboe committed
263

zwelch's avatar
zwelch committed
264
		int timeout;
zwelch's avatar
zwelch committed
265
		for (timeout = 0; timeout < 1000; timeout++) {
zwelch's avatar
zwelch committed
266
			if ((retval = target_read_u8(target, adr, &status)) != ERROR_OK)
267
268
269
			{
				return retval;
			}
270
			if (status & 0x80)
oharboe's avatar
oharboe committed
271
				break;
272
			alive_sleep(1);
oharboe's avatar
oharboe committed
273
		}
zwelch's avatar
zwelch committed
274
		if (timeout == 1000)
oharboe's avatar
oharboe committed
275
276
277
278
		{
			LOG_ERROR("erase timed out");
			return ERROR_FAIL;
		}
zwelch's avatar
zwelch committed
279

oharboe's avatar
oharboe committed
280
		/* clear status, also clear read array */
zwelch's avatar
zwelch committed
281
		if ((retval = target_write_u16(target, adr, 0x50)) != ERROR_OK)
282
283
284
		{
			return retval;
		}
zwelch's avatar
zwelch committed
285

oharboe's avatar
oharboe committed
286
		/* read array command */
zwelch's avatar
zwelch committed
287
		if ((retval = target_write_u16(target, adr, 0xFF)) != ERROR_OK)
288
289
290
		{
			return retval;
		}
zwelch's avatar
zwelch committed
291

292
		if (status & 0x22)
oharboe's avatar
oharboe committed
293
		{
294
			LOG_ERROR("error erasing flash bank, status: 0x%x", status);
oharboe's avatar
oharboe committed
295
296
			return ERROR_FLASH_OPERATION_FAILED;
		}
zwelch's avatar
zwelch committed
297

298
299
300
		/* If we ran erase bank command, we are finished */
		if (erase_cmd == 0x80)
			break;
oharboe's avatar
oharboe committed
301
	}
zwelch's avatar
zwelch committed
302

oharboe's avatar
oharboe committed
303
304
305
306
307
308
	for (i = first; i <= last; i++)
		bank->sectors[i].is_erased = 1;

	return ERROR_OK;
}

mifi's avatar
mifi committed
309
310
static int str9x_protect(struct flash_bank_s *bank,
		int set, int first, int last)
oharboe's avatar
oharboe committed
311
312
313
{
	target_t *target = bank->target;
	int i;
314
	uint32_t adr;
315
	uint8_t status;
zwelch's avatar
zwelch committed
316

oharboe's avatar
oharboe committed
317
318
	if (bank->target->state != TARGET_HALTED)
	{
oharboe's avatar
oharboe committed
319
		LOG_ERROR("Target not halted");
oharboe's avatar
oharboe committed
320
321
		return ERROR_TARGET_NOT_HALTED;
	}
zwelch's avatar
zwelch committed
322

oharboe's avatar
oharboe committed
323
324
325
	for (i = first; i <= last; i++)
	{
		/* Level One Protection */
zwelch's avatar
zwelch committed
326

oharboe's avatar
oharboe committed
327
		adr = bank->base + bank->sectors[i].offset;
zwelch's avatar
zwelch committed
328

oharboe's avatar
oharboe committed
329
		target_write_u16(target, adr, 0x60);
330
		if (set)
oharboe's avatar
oharboe committed
331
332
333
			target_write_u16(target, adr, 0x01);
		else
			target_write_u16(target, adr, 0xD0);
zwelch's avatar
zwelch committed
334

oharboe's avatar
oharboe committed
335
336
		/* query status */
		target_read_u8(target, adr, &status);
zwelch's avatar
zwelch committed
337

338
339
		/* clear status, also clear read array */
		target_write_u16(target, adr, 0x50);
zwelch's avatar
zwelch committed
340

341
342
		/* read array command */
		target_write_u16(target, adr, 0xFF);
oharboe's avatar
oharboe committed
343
	}
zwelch's avatar
zwelch committed
344

oharboe's avatar
oharboe committed
345
346
347
	return ERROR_OK;
}

mifi's avatar
mifi committed
348
static int str9x_write_block(struct flash_bank_s *bank,
349
		uint8_t *buffer, uint32_t offset, uint32_t count)
oharboe's avatar
oharboe committed
350
{
351
	struct str9x_flash_bank *str9x_info = bank->driver_priv;
oharboe's avatar
oharboe committed
352
	target_t *target = bank->target;
353
	uint32_t buffer_size = 8192;
oharboe's avatar
oharboe committed
354
	working_area_t *source;
355
	uint32_t address = bank->base + offset;
356
	struct reg_param reg_params[4];
oharboe's avatar
oharboe committed
357
	armv4_5_algorithm_t armv4_5_info;
358
	int retval = ERROR_OK;
zwelch's avatar
zwelch committed
359

360
	uint32_t str9x_flash_write_code[] = {
oharboe's avatar
oharboe committed
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
					/* write:				*/
		0xe3c14003,	/*	bic	r4, r1, #3		*/
		0xe3a03040,	/*	mov	r3, #0x40		*/
		0xe1c430b0,	/*	strh r3, [r4, #0]	*/
		0xe0d030b2,	/*	ldrh r3, [r0], #2	*/
		0xe0c130b2,	/*	strh r3, [r1], #2	*/
		0xe3a03070,	/*	mov r3, #0x70		*/
		0xe1c430b0,	/*	strh r3, [r4, #0]	*/
					/* busy:				*/
		0xe5d43000,	/*	ldrb r3, [r4, #0]	*/
		0xe3130080,	/*	tst r3, #0x80		*/
		0x0afffffc,	/*	beq busy			*/
		0xe3a05050,	/*	mov	r5, #0x50		*/
		0xe1c450b0,	/*	strh r5, [r4, #0]	*/
		0xe3a050ff,	/*	mov	r5, #0xFF		*/
		0xe1c450b0,	/*	strh r5, [r4, #0]	*/
		0xe3130012,	/*	tst	r3, #0x12		*/
		0x1a000001,	/*	bne exit			*/
		0xe2522001,	/*	subs r2, r2, #1		*/
		0x1affffed,	/*	bne write			*/
					/* exit:				*/
		0xeafffffe,	/*	b exit				*/
	};
zwelch's avatar
zwelch committed
384

oharboe's avatar
oharboe committed
385
386
387
	/* flash write code */
	if (target_alloc_working_area(target, 4 * 19, &str9x_info->write_algorithm) != ERROR_OK)
	{
388
		LOG_WARNING("no working area available, can't do block memory writes");
oharboe's avatar
oharboe committed
389
390
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	};
zwelch's avatar
zwelch committed
391

392
	target_write_buffer(target, str9x_info->write_algorithm->address, 19 * 4, (uint8_t*)str9x_flash_write_code);
oharboe's avatar
oharboe committed
393
394
395
396
397
398
399
400
401
402

	/* memory buffer */
	while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
	{
		buffer_size /= 2;
		if (buffer_size <= 256)
		{
			/* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
			if (str9x_info->write_algorithm)
				target_free_working_area(target, str9x_info->write_algorithm);
zwelch's avatar
zwelch committed
403

404
			LOG_WARNING("no large enough working area available, can't do block memory writes");
oharboe's avatar
oharboe committed
405
406
407
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
	}
zwelch's avatar
zwelch committed
408

oharboe's avatar
oharboe committed
409
410
411
	armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
	armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
	armv4_5_info.core_state = ARMV4_5_STATE_ARM;
zwelch's avatar
zwelch committed
412

oharboe's avatar
oharboe committed
413
414
415
416
	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_IN);
zwelch's avatar
zwelch committed
417

oharboe's avatar
oharboe committed
418
419
	while (count > 0)
	{
420
		uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
zwelch's avatar
zwelch committed
421

oharboe's avatar
oharboe committed
422
		target_write_buffer(target, source->address, thisrun_count * 2, buffer);
zwelch's avatar
zwelch committed
423

oharboe's avatar
oharboe committed
424
425
426
427
		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, thisrun_count);

zwelch's avatar
zwelch committed
428
		if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, str9x_info->write_algorithm->address, str9x_info->write_algorithm->address + (18 * 4), 10000, &armv4_5_info)) != ERROR_OK)
oharboe's avatar
oharboe committed
429
		{
430
			LOG_ERROR("error executing str9x flash write algorithm");
431
			retval = ERROR_FLASH_OPERATION_FAILED;
432
			break;
oharboe's avatar
oharboe committed
433
		}
zwelch's avatar
zwelch committed
434

oharboe's avatar
oharboe committed
435
436
		if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80)
		{
437
			retval = ERROR_FLASH_OPERATION_FAILED;
438
			break;
oharboe's avatar
oharboe committed
439
		}
zwelch's avatar
zwelch committed
440

oharboe's avatar
oharboe committed
441
442
443
444
		buffer += thisrun_count * 2;
		address += thisrun_count * 2;
		count -= thisrun_count;
	}
zwelch's avatar
zwelch committed
445

oharboe's avatar
oharboe committed
446
447
	target_free_working_area(target, source);
	target_free_working_area(target, str9x_info->write_algorithm);
zwelch's avatar
zwelch committed
448

oharboe's avatar
oharboe committed
449
450
451
452
	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);
	destroy_reg_param(&reg_params[3]);
zwelch's avatar
zwelch committed
453

454
	return retval;
oharboe's avatar
oharboe committed
455
456
}

mifi's avatar
mifi committed
457
static int str9x_write(struct flash_bank_s *bank,
458
		uint8_t *buffer, uint32_t offset, uint32_t count)
oharboe's avatar
oharboe committed
459
460
{
	target_t *target = bank->target;
461
462
463
464
	uint32_t words_remaining = (count / 2);
	uint32_t bytes_remaining = (count & 0x00000001);
	uint32_t address = bank->base + offset;
	uint32_t bytes_written = 0;
465
	uint8_t status;
466
	int retval;
467
468
	uint32_t check_address = offset;
	uint32_t bank_adr;
oharboe's avatar
oharboe committed
469
	int i;
zwelch's avatar
zwelch committed
470

471
472
	if (bank->target->state != TARGET_HALTED)
	{
oharboe's avatar
oharboe committed
473
		LOG_ERROR("Target not halted");
474
475
476
		return ERROR_TARGET_NOT_HALTED;
	}

oharboe's avatar
oharboe committed
477
478
	if (offset & 0x1)
	{
duane's avatar
duane committed
479
		LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
oharboe's avatar
oharboe committed
480
481
		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
	}
zwelch's avatar
zwelch committed
482

oharboe's avatar
oharboe committed
483
484
	for (i = 0; i < bank->num_sectors; i++)
	{
485
486
		uint32_t sec_start = bank->sectors[i].offset;
		uint32_t sec_end = sec_start + bank->sectors[i].size;
zwelch's avatar
zwelch committed
487

oharboe's avatar
oharboe committed
488
489
490
491
492
493
494
495
496
497
		/* 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;
		}
	}
zwelch's avatar
zwelch committed
498

oharboe's avatar
oharboe committed
499
500
	if (check_address != offset + count)
		return ERROR_FLASH_DST_OUT_OF_BANK;
zwelch's avatar
zwelch committed
501

oharboe's avatar
oharboe committed
502
	/* multiple half words (2-byte) to be programmed? */
zwelch's avatar
zwelch committed
503
	if (words_remaining > 0)
oharboe's avatar
oharboe committed
504
505
506
507
508
509
510
	{
		/* try using a block write */
		if ((retval = str9x_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
		{
			if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
			{
				/* if block write failed (no sufficient working area),
zwelch's avatar
zwelch committed
511
				 * we use normal (slow) single dword accesses */
512
				LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
oharboe's avatar
oharboe committed
513
514
515
			}
			else if (retval == ERROR_FLASH_OPERATION_FAILED)
			{
516
				LOG_ERROR("flash writing failed with error code: 0x%x", retval);
oharboe's avatar
oharboe committed
517
518
519
520
521
522
523
524
525
526
527
528
529
530
				return ERROR_FLASH_OPERATION_FAILED;
			}
		}
		else
		{
			buffer += words_remaining * 2;
			address += words_remaining * 2;
			words_remaining = 0;
		}
	}

	while (words_remaining > 0)
	{
		bank_adr = address & ~0x03;
zwelch's avatar
zwelch committed
531

oharboe's avatar
oharboe committed
532
533
		/* write data command */
		target_write_u16(target, bank_adr, 0x40);
zwelch's avatar
zwelch committed
534
		target_write_memory(target, address, 2, 1, buffer + bytes_written);
zwelch's avatar
zwelch committed
535

oharboe's avatar
oharboe committed
536
537
		/* get status command */
		target_write_u16(target, bank_adr, 0x70);
zwelch's avatar
zwelch committed
538

539
		int timeout;
zwelch's avatar
zwelch committed
540
		for (timeout = 0; timeout < 1000; timeout++)
zwelch's avatar
zwelch committed
541
		{
oharboe's avatar
oharboe committed
542
			target_read_u8(target, bank_adr, &status);
543
			if (status & 0x80)
oharboe's avatar
oharboe committed
544
				break;
545
			alive_sleep(1);
oharboe's avatar
oharboe committed
546
		}
zwelch's avatar
zwelch committed
547
		if (timeout == 1000)
oharboe's avatar
oharboe committed
548
549
550
551
		{
			LOG_ERROR("write timed out");
			return ERROR_FAIL;
		}
zwelch's avatar
zwelch committed
552

oharboe's avatar
oharboe committed
553
554
555
		/* clear status reg and read array */
		target_write_u16(target, bank_adr, 0x50);
		target_write_u16(target, bank_adr, 0xFF);
zwelch's avatar
zwelch committed
556

oharboe's avatar
oharboe committed
557
558
559
560
561
562
563
564
565
		if (status & 0x10)
			return ERROR_FLASH_OPERATION_FAILED;
		else if (status & 0x02)
			return ERROR_FLASH_OPERATION_FAILED;

		bytes_written += 2;
		words_remaining--;
		address += 2;
	}
zwelch's avatar
zwelch committed
566

oharboe's avatar
oharboe committed
567
568
	if (bytes_remaining)
	{
569
		uint8_t last_halfword[2] = {0xff, 0xff};
oharboe's avatar
oharboe committed
570
		int i = 0;
zwelch's avatar
zwelch committed
571

zwelch's avatar
zwelch committed
572
		while (bytes_remaining > 0)
oharboe's avatar
oharboe committed
573
		{
zwelch's avatar
zwelch committed
574
			last_halfword[i++] = *(buffer + bytes_written);
oharboe's avatar
oharboe committed
575
576
577
			bytes_remaining--;
			bytes_written++;
		}
zwelch's avatar
zwelch committed
578

oharboe's avatar
oharboe committed
579
		bank_adr = address & ~0x03;
zwelch's avatar
zwelch committed
580
581

		/* write data command */
oharboe's avatar
oharboe committed
582
		target_write_u16(target, bank_adr, 0x40);
zwelch's avatar
zwelch committed
583
		target_write_memory(target, address, 2, 1, last_halfword);
zwelch's avatar
zwelch committed
584

oharboe's avatar
oharboe committed
585
586
		/* query status command */
		target_write_u16(target, bank_adr, 0x70);
zwelch's avatar
zwelch committed
587

588
		int timeout;
zwelch's avatar
zwelch committed
589
		for (timeout = 0; timeout < 1000; timeout++)
zwelch's avatar
zwelch committed
590
		{
oharboe's avatar
oharboe committed
591
			target_read_u8(target, bank_adr, &status);
592
			if (status & 0x80)
oharboe's avatar
oharboe committed
593
				break;
594
			alive_sleep(1);
oharboe's avatar
oharboe committed
595
		}
zwelch's avatar
zwelch committed
596
		if (timeout == 1000)
oharboe's avatar
oharboe committed
597
598
599
600
		{
			LOG_ERROR("write timed out");
			return ERROR_FAIL;
		}
zwelch's avatar
zwelch committed
601

oharboe's avatar
oharboe committed
602
603
604
		/* clear status reg and read array */
		target_write_u16(target, bank_adr, 0x50);
		target_write_u16(target, bank_adr, 0xFF);
zwelch's avatar
zwelch committed
605

oharboe's avatar
oharboe committed
606
607
608
609
610
		if (status & 0x10)
			return ERROR_FLASH_OPERATION_FAILED;
		else if (status & 0x02)
			return ERROR_FLASH_OPERATION_FAILED;
	}
zwelch's avatar
zwelch committed
611

oharboe's avatar
oharboe committed
612
613
614
	return ERROR_OK;
}

mifi's avatar
mifi committed
615
static int str9x_probe(struct flash_bank_s *bank)
oharboe's avatar
oharboe committed
616
617
618
619
{
	return ERROR_OK;
}

mifi's avatar
mifi committed
620
#if 0
621
COMMAND_HANDLER(str9x_handle_part_id_command)
oharboe's avatar
oharboe committed
622
623
624
{
	return ERROR_OK;
}
mifi's avatar
mifi committed
625
#endif
oharboe's avatar
oharboe committed
626

mifi's avatar
mifi committed
627
static int str9x_info(struct flash_bank_s *bank, char *buf, int buf_size)
oharboe's avatar
oharboe committed
628
{
629
	snprintf(buf, buf_size, "str9x flash driver info");
oharboe's avatar
oharboe committed
630
631
632
	return ERROR_OK;
}

633
COMMAND_HANDLER(str9x_handle_flash_config_command)
oharboe's avatar
oharboe committed
634
{
635
	struct str9x_flash_bank *str9x_info;
oharboe's avatar
oharboe committed
636
	target_t *target = NULL;
zwelch's avatar
zwelch committed
637

oharboe's avatar
oharboe committed
638
639
640
641
	if (argc < 5)
	{
		return ERROR_COMMAND_SYNTAX_ERROR;
	}
zwelch's avatar
zwelch committed
642

643
644
645
646
647
648
649
650
651
652
	flash_bank_t *bank;
	int retval = flash_command_get_bank_by_num(cmd_ctx, args[0], &bank);
	if (ERROR_OK != retval)
		return retval;

	uint32_t bbsr, nbbsr, bbadr, nbbadr;
	COMMAND_PARSE_NUMBER(u32, args[1], bbsr);
	COMMAND_PARSE_NUMBER(u32, args[2], nbbsr);
	COMMAND_PARSE_NUMBER(u32, args[3], bbadr);
	COMMAND_PARSE_NUMBER(u32, args[4], nbbadr);
zwelch's avatar
zwelch committed
653

oharboe's avatar
oharboe committed
654
	str9x_info = bank->driver_priv;
zwelch's avatar
zwelch committed
655

oharboe's avatar
oharboe committed
656
	target = bank->target;
zwelch's avatar
zwelch committed
657

oharboe's avatar
oharboe committed
658
659
	if (bank->target->state != TARGET_HALTED)
	{
oharboe's avatar
oharboe committed
660
		LOG_ERROR("Target not halted");
oharboe's avatar
oharboe committed
661
662
		return ERROR_TARGET_NOT_HALTED;
	}
zwelch's avatar
zwelch committed
663

oharboe's avatar
oharboe committed
664
	/* config flash controller */
665
666
667
668
	target_write_u32(target, FLASH_BBSR, bbsr);
	target_write_u32(target, FLASH_NBBSR, nbbsr);
	target_write_u32(target, FLASH_BBADR, bbadr >> 2);
	target_write_u32(target, FLASH_NBBADR, nbbadr >> 2);
oharboe's avatar
oharboe committed
669
670
671

	/* set bit 18 instruction TCM order as per flash programming manual */
	arm966e_write_cp15(target, 62, 0x40000);
zwelch's avatar
zwelch committed
672

oharboe's avatar
oharboe committed
673
674
675
676
	/* enable flash bank 1 */
	target_write_u32(target, FLASH_CR, 0x18);
	return ERROR_OK;
}
677
678
679
680
681
682
683
684
685
686
687
688
689

static int str9x_register_commands(struct command_context_s *cmd_ctx)
{
	command_t *str9x_cmd = register_command(cmd_ctx, NULL, "str9x",
			NULL, COMMAND_ANY, "str9x flash commands");

	register_command(cmd_ctx, str9x_cmd, "flash_config",
			str9x_handle_flash_config_command, COMMAND_EXEC,
			"configure str9 flash controller");

	return ERROR_OK;
}

690
struct flash_driver str9x_flash = {
691
692
693
694
695
696
697
698
699
700
701
702
		.name = "str9x",
		.register_commands = &str9x_register_commands,
		.flash_bank_command = &str9x_flash_bank_command,
		.erase = &str9x_erase,
		.protect = &str9x_protect,
		.write = &str9x_write,
		.probe = &str9x_probe,
		.auto_probe = &str9x_probe,
		.erase_check = &default_flash_blank_check,
		.protect_check = &str9x_protect_check,
		.info = &str9x_info,
	};