at91sam7.c 33.3 KB
Newer Older
oharboe's avatar
oharboe committed
1
2
3
4
/***************************************************************************
 *   Copyright (C) 2006 by Magnus Lundin                                   *
 *   lundin@mlu.mine.nu                                                    *
 *                                                                         *
5
6
 *   Copyright (C) 2008 by Gheorghe Guran (atlas)                          *
 *                                                                         *
oharboe's avatar
oharboe committed
7
 *   This program is free software; you can redistribute it and/or modify  *
8
 *   it under the terms of the GNU General public License as published by  *
oharboe's avatar
oharboe committed
9
10
11
12
13
 *   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        *
14
15
 *   MERCHANTABILITY or FITNESS for A PARTICULAR PURPOSE.  See the         *
 *   GNU General public License for more details.                          *
oharboe's avatar
oharboe committed
16
 *                                                                         *
17
 *   You should have received a copy of the GNU General public License     *
oharboe's avatar
oharboe committed
18
19
20
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
21
****************************************************************************/
oharboe's avatar
oharboe committed
22

23
/***************************************************************************
24
25
*
* New flash setup command:
oharboe's avatar
oharboe committed
26
*
27
28
29
30
31
* flash bank <driver> <base_addr> <size> <chip_width> <bus_width> <target_id>
*	[<chip_type> <banks>
*	 <sectors_per_bank> <pages_per_sector>
*	 <page_size> <num_nvmbits>
*	 <ext_freq_khz>]
oharboe's avatar
oharboe committed
32
*
33
*   <ext_freq_khz> - MUST be used if clock is from external source,
34
*                    CAN be used if main oscillator frequency is known (recommended)
35
* Examples:
36
37
38
39
40
41
42
43
44
45
46
* ==== RECOMMENDED (covers clock speed) ============
*  flash bank at91sam7 0x00100000 0 0 4 $_TARGETNAME AT91SAM7XC256 1 16 64 256 3 25000
*			(if auto-detect fails; provides clock spec)
*  flash bank at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 25000
*			(auto-detect everything except the clock)
* ==== NOT RECOMMENDED !!! (clock speed is not configured) ====
*  flash bank at91sam7 0x00100000 0 0 4 $_TARGETNAME AT91SAM7XC256 1 16 64 256 3 0
*			(if auto-detect fails)
*  flash bank at91sam7 0 0 0 0 $_TARGETNAME
*			(old style, auto-detect everything)
****************************************************************************/
47

oharboe's avatar
oharboe committed
48
49
50
51
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

Zachary T Welch's avatar
Zachary T Welch committed
52
#include "imp.h"
53
#include <helper/binarybuffer.h>
oharboe's avatar
oharboe committed
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

/* AT91SAM7 control registers */
#define DBGU_CIDR			0xFFFFF240
#define CKGR_MCFR			0xFFFFFC24
#define CKGR_MOR			0xFFFFFC20
#define CKGR_MCFR_MAINRDY	0x10000
#define CKGR_PLLR			0xFFFFFC2c
#define CKGR_PLLR_DIV		0xff
#define CKGR_PLLR_MUL		0x07ff0000
#define PMC_MCKR			0xFFFFFC30
#define PMC_MCKR_CSS		0x03
#define PMC_MCKR_PRES		0x1c

/* Flash Controller Commands */
#define WP		0x01
#define SLB		0x02
#define WPL		0x03
#define CLB		0x04
#define EA		0x08
#define SGPB	0x0B
#define CGPB	0x0D
#define SSB		0x0F

/* MC_FSR bit definitions */
#define MC_FSR_FRDY			1
#define MC_FSR_EOL			2

/* AT91SAM7 constants */
#define RC_FREQ				32000

/* Flash timing modes */
#define FMR_TIMING_NONE		0
#define FMR_TIMING_NVBITS	1
#define FMR_TIMING_FLASH	2

/* Flash size constants */
#define FLASH_SIZE_8KB		1
#define FLASH_SIZE_16KB		2
#define FLASH_SIZE_32KB		3
#define FLASH_SIZE_64KB		5
#define FLASH_SIZE_128KB	7
#define FLASH_SIZE_256KB	9
#define FLASH_SIZE_512KB	10
#define FLASH_SIZE_1024KB	12
#define FLASH_SIZE_2048KB	14


102
103
static int at91sam7_protect_check(struct flash_bank *bank);
static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
mifi's avatar
mifi committed
104

Zachary T Welch's avatar
Zachary T Welch committed
105
static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number);
106
107
108
static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode);
static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout);
static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t pagen);
oharboe's avatar
oharboe committed
109

110
111
112
static uint32_t MC_FMR[4] = { 0xFFFFFF60, 0xFFFFFF70, 0xFFFFFF80, 0xFFFFFF90 };
static uint32_t MC_FCR[4] = { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 };
static uint32_t MC_FSR[4] = { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 };
oharboe's avatar
oharboe committed
113

mifi's avatar
mifi committed
114
static char * EPROC[8]= {"Unknown","ARM946-E","ARM7TDMI","Unknown","ARM920T","ARM926EJ-S","Unknown","Unknown"};
oharboe's avatar
oharboe committed
115

116
117
118
119
120
121
122
123
124
125
126
127
struct at91sam7_flash_bank
{
	/* chip id register */
	uint32_t cidr;
	uint16_t cidr_ext;
	uint16_t cidr_nvptyp;
	uint16_t cidr_arch;
	uint16_t cidr_sramsiz;
	uint16_t cidr_nvpsiz;
	uint16_t cidr_nvpsiz2;
	uint16_t cidr_eproc;
	uint16_t cidr_version;
128
	const char *target_name;
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159

	/* flash auto-detection */
	uint8_t  flash_autodetection;

	/* flash geometry */
	uint16_t pages_per_sector;
	uint16_t pagesize;
	uint16_t pages_in_lockregion;

	/* nv memory bits */
	uint16_t num_lockbits_on;
	uint16_t lockbits;
	uint16_t num_nvmbits;
	uint16_t num_nvmbits_on;
	uint16_t nvmbits;
	uint8_t  securitybit;

	/* 0: not init
	 * 1: fmcn for nvbits (1uS)
	 * 2: fmcn for flash (1.5uS) */
	uint8_t  flashmode;

	/* main clock status */
	uint8_t  mck_valid;
	uint32_t mck_freq;

	/* external clock frequency */
	uint32_t ext_freq;

};

mifi's avatar
mifi committed
160
161
#if 0
static long SRAMSIZ[16] = {
162
163
	-1,
	0x0400,		/*  1K */
164
165
	0x0800,		/*  2K */
	-1,
166
167
168
169
170
171
172
173
174
175
176
177
	0x1c000,	/* 112K */
	0x1000,		/*   4K */
	0x14000,	/*  80K */
	0x28000,	/* 160K */
	0x2000,		/*   8K */
	0x4000,		/*  16K */
	0x8000,		/*  32K */
	0x10000,	/*  64K */
	0x20000,	/* 128K */
	0x40000,	/* 256K */
	0x18000,	/*  96K */
	0x80000,	/* 512K */
oharboe's avatar
oharboe committed
178
};
mifi's avatar
mifi committed
179
#endif
oharboe's avatar
oharboe committed
180
181


Zachary T Welch's avatar
Zachary T Welch committed
182
static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number)
oharboe's avatar
oharboe committed
183
{
184
	uint32_t fsr;
185
	target_read_u32(target, MC_FSR[bank_number], &fsr);
186

187
	return fsr;
oharboe's avatar
oharboe committed
188
189
}

190
/* Read clock configuration and set at91sam7_info->mck_freq */
191
static void at91sam7_read_clock_info(struct flash_bank *bank)
oharboe's avatar
oharboe committed
192
{
193
	struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
Zachary T Welch's avatar
Zachary T Welch committed
194
	struct target *target = bank->target;
195
	uint32_t mckr, mcfr, pllr, mor;
196
197
198
199
200
201
202
203
204
205
	unsigned long tmp = 0, mainfreq;

	/* Read Clock Generator Main Oscillator Register */
	target_read_u32(target, CKGR_MOR, &mor);
	/* Read Clock Generator Main Clock Frequency Register */
	target_read_u32(target, CKGR_MCFR, &mcfr);
	/* Read Master Clock Register*/
	target_read_u32(target, PMC_MCKR, &mckr);
	/* Read Clock Generator PLL Register  */
	target_read_u32(target, CKGR_PLLR, &pllr);
206

207
208
	at91sam7_info->mck_valid = 0;
	at91sam7_info->mck_freq = 0;
209
	switch (mckr & PMC_MCKR_CSS)
210
211
212
213
214
215
216
	{
		case 0:			/* Slow Clock */
			at91sam7_info->mck_valid = 1;
			tmp = RC_FREQ;
			break;

		case 1:			/* Main Clock */
217
			if ((mcfr & CKGR_MCFR_MAINRDY) &&
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
				(at91sam7_info->ext_freq == 0))
			{
				at91sam7_info->mck_valid = 1;
				tmp = RC_FREQ / 16ul * (mcfr & 0xffff);
			}
			else if (at91sam7_info->ext_freq != 0)
			{
				at91sam7_info->mck_valid = 1;
				tmp = at91sam7_info->ext_freq;
			}
			break;

		case 2:			/* Reserved */
			break;

		case 3:			/* PLL Clock */
234
235
			if ((mcfr & CKGR_MCFR_MAINRDY) &&
				(at91sam7_info->ext_freq == 0))
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
			{
				target_read_u32(target, CKGR_PLLR, &pllr);
				if (!(pllr & CKGR_PLLR_DIV))
					break; /* 0 Hz */
				at91sam7_info->mck_valid = 1;
				mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff);
				/* Integer arithmetic should have sufficient precision
				 * as long as PLL is properly configured. */
				tmp = mainfreq / (pllr & CKGR_PLLR_DIV)*
					(((pllr & CKGR_PLLR_MUL) >> 16) + 1);
			}
			else if ((at91sam7_info->ext_freq != 0) &&
				((pllr&CKGR_PLLR_DIV) != 0))
			{
				at91sam7_info->mck_valid = 1;
				tmp = at91sam7_info->ext_freq / (pllr&CKGR_PLLR_DIV)*
					(((pllr & CKGR_PLLR_MUL) >> 16) + 1);
			}
			break;
	}

	/* Prescaler adjust */
258
	if ((((mckr & PMC_MCKR_PRES) >> 2) == 7) || (tmp == 0))
259
260
261
262
263
264
265
266
	{
		at91sam7_info->mck_valid = 0;
		at91sam7_info->mck_freq = 0;
	}
	else if (((mckr & PMC_MCKR_PRES) >> 2) != 0)
		at91sam7_info->mck_freq = tmp >> ((mckr & PMC_MCKR_PRES) >> 2);
	else
		at91sam7_info->mck_freq = tmp;
oharboe's avatar
oharboe committed
267
268
269
}

/* Setup the timimg registers for nvbits or normal flash */
270
static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode)
oharboe's avatar
oharboe committed
271
{
272
	uint32_t fmr, fmcn = 0, fws = 0;
273
	struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
Zachary T Welch's avatar
Zachary T Welch committed
274
	struct target *target = bank->target;
275
276
277
278
279
280
281
282
283

	if (mode && (mode != at91sam7_info->flashmode))
	{
		/* Always round up (ceil) */
		if (mode == FMR_TIMING_NVBITS)
		{
			if (at91sam7_info->cidr_arch == 0x60)
			{
				/* AT91SAM7A3 uses master clocks in 100 ns */
zwelch's avatar
zwelch committed
284
				fmcn = (at91sam7_info->mck_freq/10000000ul) + 1;
285
286
287
288
			}
			else
			{
				/* master clocks in 1uS for ARCH 0x7 types */
zwelch's avatar
zwelch committed
289
				fmcn = (at91sam7_info->mck_freq/1000000ul) + 1;
290
291
292
293
294
295
			}
		}
		else if (mode == FMR_TIMING_FLASH)
		{
			/* main clocks in 1.5uS */
			fmcn = (at91sam7_info->mck_freq/1000000ul)+
zwelch's avatar
zwelch committed
296
				(at91sam7_info->mck_freq/2000000ul) + 1;
297
298
299
300
301
302
		}

		/* hard overclocking */
		if (fmcn > 0xFF)
			fmcn = 0xFF;

zwelch's avatar
zwelch committed
303
		/* Only allow fmcn = 0 if clock period is > 30 us = 33kHz. */
304
305
		if (at91sam7_info->mck_freq <= 33333ul)
			fmcn = 0;
zwelch's avatar
zwelch committed
306
		/* Only allow fws = 0 if clock frequency is < 30 MHz. */
307
308
309
		if (at91sam7_info->mck_freq > 30000000ul)
			fws = 1;

duane's avatar
duane committed
310
		LOG_DEBUG("fmcn[%i]: %i", bank->bank_number, (int)(fmcn));
311
312
313
314
315
		fmr = fmcn << 16 | fws << 8;
		target_write_u32(target, MC_FMR[bank->bank_number], fmr);
	}

	at91sam7_info->flashmode = mode;
oharboe's avatar
oharboe committed
316
317
}

318
static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout)
oharboe's avatar
oharboe committed
319
{
320
	uint32_t status;
321
322
323

	while ((!((status = at91sam7_get_flash_status(bank->target, bank->bank_number)) & waitbits)) && (timeout-- > 0))
	{
duane's avatar
duane committed
324
		LOG_DEBUG("status[%i]: 0x%" PRIx32 "", (int)bank->bank_number, status);
325
326
327
		alive_sleep(1);
	}

duane's avatar
duane committed
328
	LOG_DEBUG("status[%i]: 0x%" PRIx32 "", bank->bank_number, status);
329
330
331

	if (status & 0x0C)
	{
duane's avatar
duane committed
332
		LOG_ERROR("status register: 0x%" PRIx32 "", status);
333
334
335
336
337
338
339
340
341
		if (status & 0x4)
			LOG_ERROR("Lock Error Bit Detected, Operation Abort");
		if (status & 0x8)
			LOG_ERROR("Invalid command and/or bad keyword, Operation Abort");
		if (status & 0x10)
			LOG_ERROR("Security Bit Set, Operation Abort");
	}

	return status;
oharboe's avatar
oharboe committed
342
343
344
}

/* Send one command to the AT91SAM flash controller */
345
static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t pagen)
oharboe's avatar
oharboe committed
346
{
347
	uint32_t fcr;
348
	struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
Zachary T Welch's avatar
Zachary T Welch committed
349
	struct target *target = bank->target;
350

351
	fcr = (0x5A << 24) | ((pagen&0x3FF) << 8) | cmd;
352
	target_write_u32(target, MC_FCR[bank->bank_number], fcr);
zwelch's avatar
zwelch committed
353
	LOG_DEBUG("Flash command: 0x%" PRIx32 ", flash bank: %i, page number: %u", fcr, bank->bank_number + 1, pagen);
354

zwelch's avatar
zwelch committed
355
	if ((at91sam7_info->cidr_arch == 0x60) && ((cmd == SLB) | (cmd == CLB)))
356
357
358
359
360
361
362
363
364
	{
		/* Lock bit manipulation on AT91SAM7A3 waits for FC_FSR bit 1, EOL */
		if (at91sam7_wait_status_busy(bank, MC_FSR_EOL, 10)&0x0C)
		{
			return ERROR_FLASH_OPERATION_FAILED;
		}
		return ERROR_OK;
	}

365
	if (at91sam7_wait_status_busy(bank, MC_FSR_FRDY, 10)&0x0C)
366
367
368
369
370
	{
		return ERROR_FLASH_OPERATION_FAILED;
	}

	return ERROR_OK;
oharboe's avatar
oharboe committed
371
372
373
}

/* Read device id register, main clock frequency register and fill in driver info structure */
374
static int at91sam7_read_part_info(struct flash_bank *bank)
oharboe's avatar
oharboe committed
375
{
376
	struct flash_bank *t_bank = bank;
377
	struct at91sam7_flash_bank *at91sam7_info;
Zachary T Welch's avatar
Zachary T Welch committed
378
	struct target *target = t_bank->target;
379

zwelch's avatar
zwelch committed
380
381
	uint16_t bnk, sec;
	uint16_t arch;
382
	uint32_t cidr;
383
	uint8_t banks_num = 0;
zwelch's avatar
zwelch committed
384
385
386
387
	uint16_t num_nvmbits = 0;
	uint16_t sectors_num = 0;
	uint16_t pages_per_sector = 0;
	uint16_t page_size = 0;
388
389
390
	uint32_t ext_freq;
	uint32_t bank_size;
	uint32_t base_address = 0;
391
	char *target_name_t = "Unknown";
392
393
394
395
396
397

	at91sam7_info = t_bank->driver_priv;

	if (at91sam7_info->cidr != 0)
	{
		/* flash already configured, update clock and check for protected sectors */
398
		struct flash_bank *fb = bank;
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
		t_bank = fb;

		while (t_bank)
		{
			/* re-calculate master clock frequency */
			at91sam7_read_clock_info(t_bank);

			/* no timming */
			at91sam7_set_flash_mode(t_bank, FMR_TIMING_NONE);

			/* check protect state */
			at91sam7_protect_check(t_bank);

			t_bank = fb->next;
			fb = t_bank;
		}

		return ERROR_OK;
	}

	/* Read and parse chip identification register */
	target_read_u32(target, DBGU_CIDR, &cidr);
	if (cidr == 0)
	{
		LOG_WARNING("Cannot identify target as an AT91SAM");
		return ERROR_FLASH_OPERATION_FAILED;
	}

	if (at91sam7_info->flash_autodetection == 0)
	{
		/* banks and sectors are already created, based on data from input file */
430
		struct flash_bank *fb = bank;
431
432
433
434
435
436
		t_bank = fb;
		while (t_bank)
		{
			at91sam7_info = t_bank->driver_priv;

			at91sam7_info->cidr = cidr;
zwelch's avatar
zwelch committed
437
438
439
440
441
442
443
			at91sam7_info->cidr_ext = (cidr >> 31)&0x0001;
			at91sam7_info->cidr_nvptyp = (cidr >> 28)&0x0007;
			at91sam7_info->cidr_arch = (cidr >> 20)&0x00FF;
			at91sam7_info->cidr_sramsiz = (cidr >> 16)&0x000F;
			at91sam7_info->cidr_nvpsiz2 = (cidr >> 12)&0x000F;
			at91sam7_info->cidr_nvpsiz = (cidr >> 8)&0x000F;
			at91sam7_info->cidr_eproc = (cidr >> 5)&0x0007;
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
			at91sam7_info->cidr_version = cidr&0x001F;

			/* calculate master clock frequency */
			at91sam7_read_clock_info(t_bank);

			/* no timming */
			at91sam7_set_flash_mode(t_bank, FMR_TIMING_NONE);

			/* check protect state */
			at91sam7_protect_check(t_bank);

			t_bank = fb->next;
			fb = t_bank;
		}

		return ERROR_OK;
	}

zwelch's avatar
zwelch committed
462
	arch = (cidr >> 20)&0x00FF;
463
464

	/* check flash size */
zwelch's avatar
zwelch committed
465
	switch ((cidr >> 8)&0x000F)
466
467
468
469
470
471
472
473
474
475
476
477
478
	{
		case FLASH_SIZE_8KB:
			break;

		case FLASH_SIZE_16KB:
			banks_num = 1;
			sectors_num = 8;
			pages_per_sector = 32;
			page_size  = 64;
			base_address = 0x00100000;
			if (arch == 0x70)
			{
				num_nvmbits = 2;
479
				target_name_t = "AT91SAM7S161/16";
480
481
482
483
484
485
486
487
488
489
490
491
			}
			break;

		case FLASH_SIZE_32KB:
			banks_num = 1;
			sectors_num = 8;
			pages_per_sector = 32;
			page_size  = 128;
			base_address = 0x00100000;
			if (arch == 0x70)
			{
				num_nvmbits = 2;
492
				target_name_t = "AT91SAM7S321/32";
493
494
495
496
			}
			if (arch == 0x72)
			{
				num_nvmbits = 3;
497
				target_name_t = "AT91SAM7SE32";
498
499
500
501
502
503
504
505
506
507
508
509
			}
			break;

		case FLASH_SIZE_64KB:
			banks_num = 1;
			sectors_num = 16;
			pages_per_sector = 32;
			page_size  = 128;
			base_address = 0x00100000;
			if (arch == 0x70)
			{
				num_nvmbits = 2;
510
				target_name_t = "AT91SAM7S64";
511
512
513
514
515
516
517
518
519
520
521
522
			}
			break;

		case FLASH_SIZE_128KB:
			banks_num = 1;
			sectors_num = 8;
			pages_per_sector = 64;
			page_size  = 256;
			base_address = 0x00100000;
			if (arch == 0x70)
			{
				num_nvmbits = 2;
523
				target_name_t = "AT91SAM7S128";
524
525
526
527
			}
			if (arch == 0x71)
			{
				num_nvmbits = 3;
528
				target_name_t = "AT91SAM7XC128";
529
530
531
532
			}
			if (arch == 0x72)
			{
				num_nvmbits = 3;
533
				target_name_t = "AT91SAM7SE128";
534
535
536
537
			}
			if (arch == 0x75)
			{
				num_nvmbits = 3;
538
				target_name_t = "AT91SAM7X128";
539
540
541
542
543
544
545
546
547
548
549
550
			}
			break;

		case FLASH_SIZE_256KB:
			banks_num = 1;
			sectors_num = 16;
			pages_per_sector = 64;
			page_size  = 256;
			base_address = 0x00100000;
			if (arch == 0x60)
			{
				num_nvmbits = 3;
551
				target_name_t = "AT91SAM7A3";
552
553
554
555
			}
			if (arch == 0x70)
			{
				num_nvmbits = 2;
556
				target_name_t = "AT91SAM7S256";
557
558
559
560
			}
			if (arch == 0x71)
			{
				num_nvmbits = 3;
561
				target_name_t = "AT91SAM7XC256";
562
563
564
565
			}
			if (arch == 0x72)
			{
				num_nvmbits = 3;
566
				target_name_t = "AT91SAM7SE256";
567
568
569
570
			}
			if (arch == 0x75)
			{
				num_nvmbits = 3;
571
				target_name_t = "AT91SAM7X256";
572
573
574
575
576
577
578
579
580
581
582
583
			}
			break;

		case FLASH_SIZE_512KB:
			banks_num = 2;
			sectors_num = 16;
			pages_per_sector = 64;
			page_size  = 256;
			base_address = 0x00100000;
			if (arch == 0x70)
			{
				num_nvmbits = 2;
584
				target_name_t = "AT91SAM7S512";
585
586
587
588
			}
			if (arch == 0x71)
			{
				num_nvmbits = 3;
589
				target_name_t = "AT91SAM7XC512";
590
591
592
593
			}
			if (arch == 0x72)
			{
				num_nvmbits = 3;
594
				target_name_t = "AT91SAM7SE512";
595
596
597
598
			}
			if (arch == 0x75)
			{
				num_nvmbits = 3;
599
				target_name_t = "AT91SAM7X512";
600
601
602
603
604
605
606
607
608
609
			}
			break;

		case FLASH_SIZE_1024KB:
			break;

		case FLASH_SIZE_2048KB:
			break;
	}

610
	if (strcmp(target_name_t, "Unknown") == 0)
611
612
613
614
615
616
617
618
619
620
	{
		LOG_ERROR("Target autodetection failed! Please specify target parameters in configuration file");
		return ERROR_FLASH_OPERATION_FAILED;
	}

	ext_freq = at91sam7_info->ext_freq;

	/* calculate bank size  */
	bank_size = sectors_num * pages_per_sector * page_size;

zwelch's avatar
zwelch committed
621
	for (bnk = 0; bnk < banks_num; bnk++)
622
623
624
625
	{
		if (bnk > 0)
		{
			/* create a new flash bank element */
626
			struct flash_bank *fb = malloc(sizeof(struct flash_bank));
627
			fb->target = target;
628
			fb->driver = bank->driver;
629
			fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank));
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
			fb->next = NULL;

			/* link created bank in 'flash_banks' list and redirect t_bank */
			t_bank->next = fb;
			t_bank = fb;
		}

		t_bank->bank_number = bnk;
		t_bank->base = base_address + bnk * bank_size;
		t_bank->size = bank_size;
		t_bank->chip_width = 0;
		t_bank->bus_width = 4;
		t_bank->num_sectors = sectors_num;

		/* allocate sectors */
645
		t_bank->sectors = malloc(sectors_num * sizeof(struct flash_sector));
zwelch's avatar
zwelch committed
646
		for (sec = 0; sec < sectors_num; sec++)
647
648
649
650
651
652
653
654
655
656
		{
			t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
			t_bank->sectors[sec].size = pages_per_sector * page_size;
			t_bank->sectors[sec].is_erased = -1;
			t_bank->sectors[sec].is_protected = -1;
		}

		at91sam7_info = t_bank->driver_priv;

		at91sam7_info->cidr = cidr;
zwelch's avatar
zwelch committed
657
658
659
660
661
662
663
		at91sam7_info->cidr_ext = (cidr >> 31)&0x0001;
		at91sam7_info->cidr_nvptyp = (cidr >> 28)&0x0007;
		at91sam7_info->cidr_arch = (cidr >> 20)&0x00FF;
		at91sam7_info->cidr_sramsiz = (cidr >> 16)&0x000F;
		at91sam7_info->cidr_nvpsiz2 = (cidr >> 12)&0x000F;
		at91sam7_info->cidr_nvpsiz = (cidr >> 8)&0x000F;
		at91sam7_info->cidr_eproc = (cidr >> 5)&0x0007;
664
665
		at91sam7_info->cidr_version = cidr&0x001F;

666
		at91sam7_info->target_name  = target_name_t;
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
		at91sam7_info->flashmode = 0;
		at91sam7_info->ext_freq = ext_freq;
		at91sam7_info->num_nvmbits = num_nvmbits;
		at91sam7_info->num_nvmbits_on = 0;
		at91sam7_info->pagesize = page_size;
		at91sam7_info->pages_per_sector = pages_per_sector;

		/* calculate master clock frequency */
		at91sam7_read_clock_info(t_bank);

		/* no timming */
		at91sam7_set_flash_mode(t_bank, FMR_TIMING_NONE);

		/* check protect state */
		at91sam7_protect_check(t_bank);
	}

684
	LOG_DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x", at91sam7_info->cidr_nvptyp, at91sam7_info->cidr_arch);
685
686

	return ERROR_OK;
oharboe's avatar
oharboe committed
687
688
}

689
static int at91sam7_erase_check(struct flash_bank *bank)
oharboe's avatar
oharboe committed
690
{
Zachary T Welch's avatar
Zachary T Welch committed
691
	struct target *target = bank->target;
zwelch's avatar
zwelch committed
692
	uint16_t retval;
693
	uint32_t blank;
zwelch's avatar
zwelch committed
694
	uint16_t fast_check;
695
	uint8_t *buffer;
zwelch's avatar
zwelch committed
696
697
	uint16_t nSector;
	uint16_t nByte;
698
699
700
701
702
703
704
705

	if (bank->target->state != TARGET_HALTED)
	{
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	/* Configure the flash controller timing */
706
	at91sam7_read_clock_info(bank);
707
708
709
	at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);

	fast_check = 1;
zwelch's avatar
zwelch committed
710
	for (nSector = 0; nSector < bank->num_sectors; nSector++)
711
	{
zwelch's avatar
zwelch committed
712
		retval = target_blank_check_memory(target, bank->base + bank->sectors[nSector].offset,
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
			bank->sectors[nSector].size, &blank);
		if (retval != ERROR_OK)
		{
			fast_check = 0;
			break;
		}
		if (blank == 0xFF)
			bank->sectors[nSector].is_erased = 1;
		else
			bank->sectors[nSector].is_erased = 0;
	}

	if (fast_check)
	{
		return ERROR_OK;
	}

	LOG_USER("Running slow fallback erase check - add working memory");

	buffer = malloc(bank->sectors[0].size);
zwelch's avatar
zwelch committed
733
	for (nSector = 0; nSector < bank->num_sectors; nSector++)
734
735
	{
		bank->sectors[nSector].is_erased = 1;
zwelch's avatar
zwelch committed
736
		retval = target_read_memory(target, bank->base + bank->sectors[nSector].offset, 4,
737
738
739
740
			bank->sectors[nSector].size/4, buffer);
		if (retval != ERROR_OK)
			return retval;

zwelch's avatar
zwelch committed
741
		for (nByte = 0; nByte < bank->sectors[nSector].size; nByte++)
742
743
744
745
746
747
748
749
750
751
752
		{
			if (buffer[nByte] != 0xFF)
			{
				bank->sectors[nSector].is_erased = 0;
				break;
			}
		}
	}
	free(buffer);

	return ERROR_OK;
oharboe's avatar
oharboe committed
753
754
}

755
static int at91sam7_protect_check(struct flash_bank *bank)
oharboe's avatar
oharboe committed
756
{
757
	uint8_t lock_pos, gpnvm_pos;
758
	uint32_t status;
759

760
	struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
761
762
763
764
765
766
767
768
769
770
771
772

	if (at91sam7_info->cidr == 0)
	{
		return ERROR_FLASH_BANK_NOT_PROBED;
	}
	if (bank->target->state != TARGET_HALTED)
	{
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	status = at91sam7_get_flash_status(bank->target, bank->bank_number);
zwelch's avatar
zwelch committed
773
	at91sam7_info->lockbits = (status >> 16);
774
775

	at91sam7_info->num_lockbits_on = 0;
zwelch's avatar
zwelch committed
776
	for (lock_pos = 0; lock_pos < bank->num_sectors; lock_pos++)
777
	{
778
		if (((status >> (16 + lock_pos))&(0x0001)) == 1)
779
780
781
782
783
784
785
786
787
788
789
		{
			at91sam7_info->num_lockbits_on++;
			bank->sectors[lock_pos].is_protected = 1;
		}
		else
			bank->sectors[lock_pos].is_protected = 0;
	}

	/* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */
	status = at91sam7_get_flash_status(bank->target, 0);

zwelch's avatar
zwelch committed
790
791
	at91sam7_info->securitybit = (status >> 4)&0x01;
	at91sam7_info->nvmbits = (status >> 8)&0xFF;
792
793

	at91sam7_info->num_nvmbits_on = 0;
zwelch's avatar
zwelch committed
794
	for (gpnvm_pos = 0; gpnvm_pos < at91sam7_info->num_nvmbits; gpnvm_pos++)
795
	{
796
		if (((status >> (8 + gpnvm_pos))&(0x01)) == 1)
797
798
799
800
801
802
		{
			at91sam7_info->num_nvmbits_on++;
		}
	}

	return ERROR_OK;
oharboe's avatar
oharboe committed
803
804
}

805
FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
oharboe's avatar
oharboe committed
806
{
807
	struct flash_bank *t_bank = bank;
808
	struct at91sam7_flash_bank *at91sam7_info;
Zachary T Welch's avatar
Zachary T Welch committed
809
	struct target *target = t_bank->target;
810

811
812
	uint32_t base_address;
	uint32_t bank_size;
813
	uint32_t ext_freq = 0;
814
815
816
817
818
819

	int chip_width;
	int bus_width;
	int banks_num;
	int num_sectors;

zwelch's avatar
zwelch committed
820
821
822
	uint16_t pages_per_sector;
	uint16_t page_size;
	uint16_t num_nvmbits;
823

824
	char *target_name_t;
825
826
827

	int bnk, sec;

828
	at91sam7_info = malloc(sizeof(struct at91sam7_flash_bank));
829
830
831
832
833
834
835
836
	t_bank->driver_priv = at91sam7_info;

	/* part wasn't probed for info yet */
	at91sam7_info->cidr = 0;
	at91sam7_info->flashmode = 0;
	at91sam7_info->ext_freq = 0;
	at91sam7_info->flash_autodetection = 0;

837
	if (CMD_ARGC < 13)
838
	{
839
840
841
842
		at91sam7_info->flash_autodetection = 1;
		return ERROR_OK;
	}

843
	COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], base_address);
844

845
846
	COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], chip_width);
	COMMAND_PARSE_NUMBER(int, CMD_ARGV[4], bus_width);
847

848
849
850
851
852
	COMMAND_PARSE_NUMBER(int, CMD_ARGV[8], banks_num);
	COMMAND_PARSE_NUMBER(int, CMD_ARGV[9], num_sectors);
	COMMAND_PARSE_NUMBER(u16, CMD_ARGV[10], pages_per_sector);
	COMMAND_PARSE_NUMBER(u16, CMD_ARGV[11], page_size);
	COMMAND_PARSE_NUMBER(u16, CMD_ARGV[12], num_nvmbits);
853

854
	if (CMD_ARGC == 14) {
855
		unsigned long freq;
856
		COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[13], freq);
857
		ext_freq = freq * 1000;
858
859
860
		at91sam7_info->ext_freq = ext_freq;
	}

861
862
	if ((bus_width == 0) || (banks_num == 0) || (num_sectors == 0) ||
		(pages_per_sector == 0) || (page_size == 0) || (num_nvmbits == 0))
863
864
865
866
867
	{
		at91sam7_info->flash_autodetection = 1;
		return ERROR_OK;
	}

868
869
	target_name_t = calloc(strlen(CMD_ARGV[7]) + 1, sizeof(char));
	strcpy(target_name_t, CMD_ARGV[7]);
870
871
872
873

	/* calculate bank size  */
	bank_size = num_sectors * pages_per_sector * page_size;

zwelch's avatar
zwelch committed
874
	for (bnk = 0; bnk < banks_num; bnk++)
875
876
877
878
	{
		if (bnk > 0)
		{
			/* create a new bank element */
879
			struct flash_bank *fb = malloc(sizeof(struct flash_bank));
880
			fb->target = target;
881
			fb->driver = bank->driver;
882
			fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank));
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
			fb->next = NULL;

			/* link created bank in 'flash_banks' list and redirect t_bank */
			t_bank->next = fb;
			t_bank = fb;
		}

		t_bank->bank_number = bnk;
		t_bank->base = base_address + bnk * bank_size;
		t_bank->size = bank_size;
		t_bank->chip_width = chip_width;
		t_bank->bus_width = bus_width;
		t_bank->num_sectors = num_sectors;

		/* allocate sectors */
898
		t_bank->sectors = malloc(num_sectors * sizeof(struct flash_sector));
zwelch's avatar
zwelch committed
899
		for (sec = 0; sec < num_sectors; sec++)
900
901
902
903
904
905
906
907
908
		{
			t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
			t_bank->sectors[sec].size = pages_per_sector * page_size;
			t_bank->sectors[sec].is_erased = -1;
			t_bank->sectors[sec].is_protected = -1;
		}

		at91sam7_info = t_bank->driver_priv;

909
		at91sam7_info->target_name  = target_name_t;
910
911
912
913
914
915
916
917
918
		at91sam7_info->flashmode = 0;
		at91sam7_info->ext_freq  = ext_freq;
		at91sam7_info->num_nvmbits = num_nvmbits;
		at91sam7_info->num_nvmbits_on = 0;
		at91sam7_info->pagesize = page_size;
		at91sam7_info->pages_per_sector = pages_per_sector;
	}

	return ERROR_OK;
oharboe's avatar
oharboe committed
919
920
}

921
static int at91sam7_erase(struct flash_bank *bank, int first, int last)
oharboe's avatar
oharboe committed
922
{
923
	struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
924
	int sec;
925
	uint32_t nbytes, pos;
926
927
	uint8_t *buffer;
	uint8_t erase_all;
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954

	if (at91sam7_info->cidr == 0)
	{
		return ERROR_FLASH_BANK_NOT_PROBED;
	}

	if (bank->target->state != TARGET_HALTED)
	{
		LOG_ERROR("Target not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	if ((first < 0) || (last < first) || (last >= bank->num_sectors))
	{
		return ERROR_FLASH_SECTOR_INVALID;
	}

	erase_all = 0;
	if ((first == 0) && (last == (bank->num_sectors-1)))
	{
		erase_all = 1;
	}

	/* Configure the flash controller timing */
	at91sam7_read_clock_info(bank);
	at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);

zwelch's avatar
zwelch committed
955
	if (erase_all)
956
	{
957
		if (at91sam7_flash_command(bank, EA, 0) != ERROR_OK)
958
959
960
961
962
963
964
965
		{
			return ERROR_FLASH_OPERATION_FAILED;
		}
	}
	else
	{
		/* allocate and clean buffer  */
		nbytes = (last - first + 1) * bank->sectors[first].size;
966
		buffer = malloc(nbytes * sizeof(uint8_t));
zwelch's avatar
zwelch committed
967
		for (pos = 0; pos < nbytes; pos++)
968
969
970
971
		{
			buffer[pos] = 0xFF;
		}

972
		if (at91sam7_write(bank, buffer, bank->sectors[first].offset, nbytes) != ERROR_OK)
973
974
975
976
977
978
979
980
		{
			return ERROR_FLASH_OPERATION_FAILED;
		}

		free(buffer);
	}

	/* mark erased sectors */
zwelch's avatar
zwelch committed
981
	for (sec = first; sec <= last; sec++)
982
983
984
985
986
	{
		bank->sectors[sec].is_erased = 1;
	}

	return ERROR_OK;
oharboe's avatar
oharboe committed
987
988
}

989
static int at91sam7_protect(struct flash_bank *bank, int set, int first, int last)
oharboe's avatar
oharboe committed
990
{
991
	uint32_t cmd;
992
	int sector;
993
	uint32_t pagen;
994

995
	struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
996
997
998
999
1000

	if (at91sam7_info->cidr == 0)
	{
		return ERROR_FLASH_BANK_NOT_PROBED;
	}
For faster browsing, not all history is shown. View entire blame