mflash.c 35.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/***************************************************************************
 *   Copyright (C) 2007-2008 by unsik Kim <donari75@gmail.com>             *
 *                                                                         *
 *   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

24
#include "mflash.h"
25
26
#include "time_support.h"
#include "fileio.h"
27
28
#include "log.h"

29
30

static int s3c2440_set_gpio_to_output (mflash_gpio_num_t gpio);
31
static int s3c2440_set_gpio_output_val (mflash_gpio_num_t gpio, uint8_t val);
32
static int pxa270_set_gpio_to_output (mflash_gpio_num_t gpio);
33
static int pxa270_set_gpio_output_val (mflash_gpio_num_t gpio, uint8_t val);
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

static command_t *mflash_cmd;

static mflash_bank_t *mflash_bank;

static mflash_gpio_drv_t pxa270_gpio = {
	.name = "pxa270",
	.set_gpio_to_output = pxa270_set_gpio_to_output,
	.set_gpio_output_val = pxa270_set_gpio_output_val
};

static mflash_gpio_drv_t s3c2440_gpio = {
	.name = "s3c2440",
	.set_gpio_to_output = s3c2440_set_gpio_to_output,
	.set_gpio_output_val = s3c2440_set_gpio_output_val
};

static mflash_gpio_drv_t *mflash_gpio[] =
{
		&pxa270_gpio,
		&s3c2440_gpio,
		NULL
};

#define PXA270_GAFR0_L 0x40E00054
#define PXA270_GAFR3_U 0x40E00070
#define PXA270_GAFR3_U_RESERVED_BITS  0xfffc0000u
#define PXA270_GPDR0 0x40E0000C
#define PXA270_GPDR3 0x40E0010C
#define PXA270_GPDR3_RESERVED_BITS  0xfe000000u
#define PXA270_GPSR0 0x40E00018
#define PXA270_GPCR0 0x40E00024

static int pxa270_set_gpio_to_output (mflash_gpio_num_t gpio)
{
69
	uint32_t addr, value, mask;
70
71
72
	target_t *target = mflash_bank->target;
	int ret;

73
	/* remove alternate function. */
74
75
76
77
78
79
80
81
82
83
84
85
86
87
	mask = 0x3u << (gpio.num & 0xF)*2;

	addr = PXA270_GAFR0_L + (gpio.num >> 4) * 4;

	if ((ret = target_read_u32(target, addr, &value)) != ERROR_OK)
		return ret;

	value &= ~mask;
	if (addr == PXA270_GAFR3_U)
		value &= ~PXA270_GAFR3_U_RESERVED_BITS;

	if ((ret = target_write_u32(target, addr, value)) != ERROR_OK)
		return ret;

88
	/* set direction to output */
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
	mask = 0x1u << (gpio.num & 0x1F);

	addr = PXA270_GPDR0 + (gpio.num >> 5) * 4;

	if ((ret = target_read_u32(target, addr, &value)) != ERROR_OK)
		return ret;

	value |= mask;
	if (addr == PXA270_GPDR3)
		value &= ~PXA270_GPDR3_RESERVED_BITS;

	ret = target_write_u32(target, addr, value);
	return ret;
}

104
static int pxa270_set_gpio_output_val (mflash_gpio_num_t gpio, uint8_t val)
105
{
106
	uint32_t addr, value, mask;
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
	target_t *target = mflash_bank->target;
	int ret;

	mask = 0x1u << (gpio.num & 0x1F);

	if (val) {
		addr = PXA270_GPSR0 + (gpio.num >> 5) * 4;
	} else {
		addr = PXA270_GPCR0 + (gpio.num >> 5) * 4;
	}

	if ((ret = target_read_u32(target, addr, &value)) != ERROR_OK)
		return ret;

	value |= mask;

	ret = target_write_u32(target, addr, value);

	return ret;
}

#define S3C2440_GPACON 0x56000000
#define S3C2440_GPADAT 0x56000004
#define S3C2440_GPJCON 0x560000d0
#define S3C2440_GPJDAT 0x560000d4

static int s3c2440_set_gpio_to_output (mflash_gpio_num_t gpio)
{
135
	uint32_t data, mask, gpio_con;
136
137
138
139
140
141
142
143
	target_t *target = mflash_bank->target;
	int ret;

	if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') {
		gpio_con = S3C2440_GPACON + (gpio.port[0] - 'a') * 0x10;
	} else if (gpio.port[0] == 'j') {
		gpio_con = S3C2440_GPJCON;
	} else {
zwelch's avatar
zwelch committed
144
		LOG_ERROR("mflash: invalid port %d%s", gpio.num, gpio.port);
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
		return ERROR_INVALID_ARGUMENTS;
	}

	ret = target_read_u32(target, gpio_con, &data);

	if (ret == ERROR_OK) {
		if (gpio.port[0] == 'a') {
			mask = 1 << gpio.num;
			data &= ~mask;
		} else {
			mask = 3 << gpio.num * 2;
			data &= ~mask;
			data |= (1 << gpio.num * 2);
		}

		ret = target_write_u32(target, gpio_con, data);
	}
	return ret;
}

165
static int s3c2440_set_gpio_output_val (mflash_gpio_num_t gpio, uint8_t val)
166
{
167
	uint32_t data, mask, gpio_dat;
168
169
170
171
172
173
174
175
	target_t *target = mflash_bank->target;
	int ret;

	if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') {
		gpio_dat = S3C2440_GPADAT + (gpio.port[0] - 'a') * 0x10;
	} else if (gpio.port[0] == 'j') {
		gpio_dat = S3C2440_GPJDAT;
	} else {
zwelch's avatar
zwelch committed
176
		LOG_ERROR("mflash: invalid port %d%s", gpio.num, gpio.port);
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
		return ERROR_INVALID_ARGUMENTS;
	}

	ret = target_read_u32(target, gpio_dat, &data);

	if (ret == ERROR_OK) {
		mask = 1 << gpio.num;
		if (val)
			data |= mask;
		else
			data &= ~mask;

		ret = target_write_u32(target, gpio_dat, data);
	}
	return ret;
}

194
static int mg_hdrst(uint8_t level)
195
196
197
198
{
	return mflash_bank->gpio_drv->set_gpio_output_val(mflash_bank->rst_pin, level);
}

zwelch's avatar
zwelch committed
199
static int mg_init_gpio (void)
200
{
zwelch's avatar
zwelch committed
201
	int ret;
202
203
	mflash_gpio_drv_t *gpio_drv = mflash_bank->gpio_drv;

zwelch's avatar
zwelch committed
204
205
206
	ret = gpio_drv->set_gpio_to_output(mflash_bank->rst_pin);
	if (ret != ERROR_OK)
		return ret;
207

zwelch's avatar
zwelch committed
208
209
210
	ret = gpio_drv->set_gpio_output_val(mflash_bank->rst_pin, 1);

	return ret;
211
212
}

213
static int mg_dsk_wait(mg_io_type_wait wait, uint32_t time)
214
{
215
	uint8_t status, error;
216
	target_t *target = mflash_bank->target;
217
	uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET;
218
	duration_t duration;
zwelch's avatar
zwelch committed
219
	int ret;
220
221
222
223
	long long t=0;

	duration_start_measure(&duration);

224
225
	while (time) {

zwelch's avatar
zwelch committed
226
227
228
		ret = target_read_u8(target, mg_task_reg + MG_REG_STATUS, &status);
		if (ret != ERROR_OK)
			return ret;
229
230
231
232
233
234

		if (status & mg_io_rbit_status_busy)
		{
			if (wait == mg_io_wait_bsy)
				return ERROR_OK;
		} else {
zwelch's avatar
zwelch committed
235
			switch (wait)
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
			{
				case mg_io_wait_not_bsy:
					return ERROR_OK;
				case mg_io_wait_rdy_noerr:
					if (status & mg_io_rbit_status_ready)
						return ERROR_OK;
					break;
				case mg_io_wait_drq_noerr:
					if (status & mg_io_rbit_status_data_req)
						return ERROR_OK;
					break;
				default:
					break;
			}

			/* Now we check the error condition! */
			if (status & mg_io_rbit_status_error)
			{
zwelch's avatar
zwelch committed
254
255
256
				ret = target_read_u8(target, mg_task_reg + MG_REG_ERROR, &error);
				if (ret != ERROR_OK)
					return ret;
257

zwelch's avatar
zwelch committed
258
259
260
				LOG_ERROR("mflash: io error 0x%02x", error);

				return ERROR_MG_IO;
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
			}

			switch (wait)
			{
				case mg_io_wait_rdy:
					if (status & mg_io_rbit_status_ready)
						return ERROR_OK;

				case mg_io_wait_drq:
					if (status & mg_io_rbit_status_data_req)
						return ERROR_OK;

				default:
					break;
			}
		}

		duration_stop_measure(&duration, NULL);

		t=duration.duration.tv_usec/1000;
zwelch's avatar
zwelch committed
281
		t += duration.duration.tv_sec*1000;
282
283

		if (t > time)
284
285
			break;
	}
286

zwelch's avatar
zwelch committed
287
288
	LOG_ERROR("mflash: timeout occured");
	return ERROR_MG_TIMEOUT;
289
290
}

291
static int mg_dsk_srst(uint8_t on)
292
293
{
	target_t *target = mflash_bank->target;
294
	uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET;
295
	uint8_t value;
296
297
298
299
300
	int ret;

	if ((ret = target_read_u8(target, mg_task_reg + MG_REG_DRV_CTRL, &value)) != ERROR_OK)
		return ret;

zwelch's avatar
zwelch committed
301
	if (on) {
302
303
304
305
306
307
308
309
310
		value |= (mg_io_rbit_devc_srst);
	} else {
		value &= ~mg_io_rbit_devc_srst;
	}

	ret = target_write_u8(target, mg_task_reg + MG_REG_DRV_CTRL, value);
	return ret;
}

311
static int mg_dsk_io_cmd(uint32_t sect_num, uint32_t cnt, uint8_t cmd)
312
313
{
	target_t *target = mflash_bank->target;
314
	uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET;
315
	uint8_t value;
zwelch's avatar
zwelch committed
316
	int ret;
317

zwelch's avatar
zwelch committed
318
319
320
	ret = mg_dsk_wait(mg_io_wait_rdy_noerr, MG_OEM_DISK_WAIT_TIME_NORMAL);
	if (ret != ERROR_OK)
		return ret;
321
322
323

	value = mg_io_rval_dev_drv_master | mg_io_rval_dev_lba_mode |((sect_num >> 24) & 0xf);

zwelch's avatar
zwelch committed
324
	ret = target_write_u8(target, mg_task_reg + MG_REG_DRV_HEAD, value);
325
326
327
328
	ret |= target_write_u8(target, mg_task_reg + MG_REG_SECT_CNT, (uint8_t)cnt);
	ret |= target_write_u8(target, mg_task_reg + MG_REG_SECT_NUM, (uint8_t)sect_num);
	ret |= target_write_u8(target, mg_task_reg + MG_REG_CYL_LOW, (uint8_t)(sect_num >> 8));
	ret |= target_write_u8(target, mg_task_reg + MG_REG_CYL_HIGH, (uint8_t)(sect_num >> 16));
329

zwelch's avatar
zwelch committed
330
331
	if (ret != ERROR_OK)
		return ret;
332

zwelch's avatar
zwelch committed
333
	return target_write_u8(target, mg_task_reg + MG_REG_COMMAND, cmd);
334
335
336
337
338
}

static int mg_dsk_drv_info(void)
{
	target_t *target = mflash_bank->target;
339
	uint32_t mg_buff = mflash_bank->base + MG_BUFFER_OFFSET;
zwelch's avatar
zwelch committed
340
	int ret;
341

zwelch's avatar
zwelch committed
342
343
	if ((ret =  mg_dsk_io_cmd(0, 1, mg_io_cmd_identify)) != ERROR_OK)
		return ret;
344

zwelch's avatar
zwelch committed
345
346
	if ((ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL)) != ERROR_OK)
		return ret;
347

zwelch's avatar
zwelch committed
348
	LOG_INFO("mflash: read drive info");
349
350
351
352

	if (! mflash_bank->drv_info)
		mflash_bank->drv_info = malloc(sizeof(mg_drv_info_t));

zwelch's avatar
zwelch committed
353
	target_read_memory(target, mg_buff, 2, sizeof(mg_io_type_drv_info) >> 1,
354
			(uint8_t *)&mflash_bank->drv_info->drv_id);
zwelch's avatar
zwelch committed
355
356
	if (ret != ERROR_OK)
		return ret;
357

358
	mflash_bank->drv_info->tot_sects = (uint32_t)(mflash_bank->drv_info->drv_id.total_user_addressable_sectors_hi << 16)
359
360
									+ mflash_bank->drv_info->drv_id.total_user_addressable_sectors_lo;

zwelch's avatar
zwelch committed
361
	return target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_read);
362
363
}

zwelch's avatar
zwelch committed
364
static int mg_mflash_rst(void)
365
{
zwelch's avatar
zwelch committed
366
	int ret;
367

zwelch's avatar
zwelch committed
368
369
	if ((ret = mg_init_gpio()) != ERROR_OK)
		return ret;
370

zwelch's avatar
zwelch committed
371
372
	if ((ret = mg_hdrst(0)) != ERROR_OK)
		return ret;
373

zwelch's avatar
zwelch committed
374
375
	if ((ret = mg_dsk_wait(mg_io_wait_bsy, MG_OEM_DISK_WAIT_TIME_LONG)) != ERROR_OK)
		return ret;
376

zwelch's avatar
zwelch committed
377
378
	if ((ret = mg_hdrst(1)) != ERROR_OK)
		return ret;
379

zwelch's avatar
zwelch committed
380
381
	if ((ret = mg_dsk_wait(mg_io_wait_not_bsy, MG_OEM_DISK_WAIT_TIME_LONG)) != ERROR_OK)
		return ret;
382

zwelch's avatar
zwelch committed
383
384
	if ((ret = mg_dsk_srst(1)) != ERROR_OK)
		return ret;
385

zwelch's avatar
zwelch committed
386
387
	if ((ret = mg_dsk_wait(mg_io_wait_bsy, MG_OEM_DISK_WAIT_TIME_LONG)) != ERROR_OK)
		return ret;
388

zwelch's avatar
zwelch committed
389
390
391
392
393
	if ((ret = mg_dsk_srst(0)) != ERROR_OK)
		return ret;

	if ((ret = mg_dsk_wait(mg_io_wait_not_bsy, MG_OEM_DISK_WAIT_TIME_LONG)) != ERROR_OK)
		return ret;
394

zwelch's avatar
zwelch committed
395
396
397
398
399
400
401
	LOG_INFO("mflash: reset ok");

	return ERROR_OK;
}

static int mg_mflash_probe(void)
{
zwelch's avatar
zwelch committed
402
	int ret;
zwelch's avatar
zwelch committed
403

zwelch's avatar
zwelch committed
404
405
	if ((ret = mg_mflash_rst()) != ERROR_OK)
		return ret;
406

zwelch's avatar
zwelch committed
407
	return mg_dsk_drv_info();
408
409
}

zwelch's avatar
zwelch committed
410
static int mg_probe_cmd(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
411
412
413
414
415
416
{
	int ret;

	ret = mg_mflash_probe();

	if (ret == ERROR_OK) {
duane's avatar
duane committed
417
		command_print(cmd_ctx, "mflash (total %" PRIu32 " sectors) found at 0x%8.8" PRIx32 "",
418
419
420
421
422
423
				mflash_bank->drv_info->tot_sects, mflash_bank->base );
	}

	return ret;
}

424
static int mg_mflash_do_read_sects(void *buff, uint32_t sect_num, uint32_t sect_cnt)
425
{
426
	uint32_t i, address;
427
428
	int ret;
	target_t *target = mflash_bank->target;
429
	uint8_t *buff_ptr = buff;
430
431
	duration_t duration;

zwelch's avatar
zwelch committed
432
433
	if ((ret = mg_dsk_io_cmd(sect_num, sect_cnt, mg_io_cmd_read)) != ERROR_OK )
		return ret;
434
435
436
437
438
439

	address = mflash_bank->base + MG_BUFFER_OFFSET;

	duration_start_measure(&duration);

	for (i = 0; i < sect_cnt; i++) {
zwelch's avatar
zwelch committed
440
441
442
443
444
445
446
		ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL);
		if (ret != ERROR_OK)
			return ret;

		ret = target_read_memory(target, address, 2, MG_MFLASH_SECTOR_SIZE / 2, buff_ptr);
		if (ret != ERROR_OK)
			return ret;
447
448
449

		buff_ptr += MG_MFLASH_SECTOR_SIZE;

zwelch's avatar
zwelch committed
450
451
452
		ret = target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_read);
		if (ret != ERROR_OK)
			return ret;
453

duane's avatar
duane committed
454
		LOG_DEBUG("mflash: %" PRIu32 " (0x%8.8" PRIx32 ") sector read", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE);
455
456
457
458

		duration_stop_measure(&duration, NULL);

		if ((duration.duration.tv_sec * 1000 + duration.duration.tv_usec / 1000) > 3000) {
duane's avatar
duane committed
459
			LOG_INFO("mflash: read %" PRIu32 "'th sectors", sect_num + i);
460
461
462
463
			duration_start_measure(&duration);
		}
	}

zwelch's avatar
zwelch committed
464
	return mg_dsk_wait(mg_io_wait_rdy, MG_OEM_DISK_WAIT_TIME_NORMAL);
465
466
}

467
static int mg_mflash_read_sects(void *buff, uint32_t sect_num, uint32_t sect_cnt)
468
{
469
	uint32_t quotient, residue, i;
470
	uint8_t *buff_ptr = buff;
zwelch's avatar
zwelch committed
471
	int ret = ERROR_OK;
472
473
474
475
476

	quotient = sect_cnt >> 8;
	residue = sect_cnt % 256;

	for (i = 0; i < quotient; i++) {
duane's avatar
duane committed
477
		LOG_DEBUG("mflash: sect num : %" PRIu32 " buff : 0x%0lx", sect_num, 
478
			(unsigned long)buff_ptr);
zwelch's avatar
zwelch committed
479
480
481
482
		ret = mg_mflash_do_read_sects(buff_ptr, sect_num, 256);
		if (ret != ERROR_OK)
			return ret;

483
484
485
486
487
		sect_num += 256;
		buff_ptr += 256 * MG_MFLASH_SECTOR_SIZE;
	}

	if (residue) {
duane's avatar
duane committed
488
		LOG_DEBUG("mflash: sect num : %" PRIx32 " buff : %0lx", sect_num, 
489
			(unsigned long)buff_ptr);
zwelch's avatar
zwelch committed
490
		return mg_mflash_do_read_sects(buff_ptr, sect_num, residue);
491
492
	}

zwelch's avatar
zwelch committed
493
	return ret;
494
495
}

496
static int mg_mflash_do_write_sects(void *buff, uint32_t sect_num, uint32_t sect_cnt,
zwelch's avatar
zwelch committed
497
		mg_io_type_cmd cmd)
498
{
499
	uint32_t i, address;
500
501
	int ret;
	target_t *target = mflash_bank->target;
502
	uint8_t *buff_ptr = buff;
503
504
	duration_t duration;

zwelch's avatar
zwelch committed
505
506
	if ((ret = mg_dsk_io_cmd(sect_num, sect_cnt, cmd)) != ERROR_OK )
		return ret;
507
508
509
510
511
512
513
514

	address = mflash_bank->base + MG_BUFFER_OFFSET;

	duration_start_measure(&duration);

	for (i = 0; i < sect_cnt; i++) {
		ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL);
		if (ret != ERROR_OK)
zwelch's avatar
zwelch committed
515
			return ret;
516

zwelch's avatar
zwelch committed
517
		ret = target_write_memory(target, address, 2, MG_MFLASH_SECTOR_SIZE / 2, buff_ptr);
518
		if (ret != ERROR_OK)
zwelch's avatar
zwelch committed
519
520
			return ret;
		
521
522
523
524
		buff_ptr += MG_MFLASH_SECTOR_SIZE;

		ret = target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_write);
		if (ret != ERROR_OK)
zwelch's avatar
zwelch committed
525
			return ret;
526

duane's avatar
duane committed
527
		LOG_DEBUG("mflash: %" PRIu32 " (0x%8.8" PRIx32 ") sector write", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE);
528
529
530
531

		duration_stop_measure(&duration, NULL);

		if ((duration.duration.tv_sec * 1000 + duration.duration.tv_usec / 1000) > 3000) {
duane's avatar
duane committed
532
			LOG_INFO("mflash: wrote %" PRIu32 "'th sectors", sect_num + i);
533
534
535
536
			duration_start_measure(&duration);
		}
	}

zwelch's avatar
zwelch committed
537
538
539
540
	if (cmd == mg_io_cmd_write)
		ret = mg_dsk_wait(mg_io_wait_rdy, MG_OEM_DISK_WAIT_TIME_NORMAL);
	else
		ret = mg_dsk_wait(mg_io_wait_rdy, MG_OEM_DISK_WAIT_TIME_LONG);
541
542
543
544

	return ret;
}

545
static int mg_mflash_write_sects(void *buff, uint32_t sect_num, uint32_t sect_cnt)
546
{
547
	uint32_t quotient, residue, i;
548
	uint8_t *buff_ptr = buff;
zwelch's avatar
zwelch committed
549
	int ret = ERROR_OK;
550
551
552
553
554

	quotient = sect_cnt >> 8;
	residue = sect_cnt % 256;

	for (i = 0; i < quotient; i++) {
duane's avatar
duane committed
555
556
		LOG_DEBUG("mflash: sect num : %" PRIu32 "buff : %p", sect_num, 
			buff_ptr);
zwelch's avatar
zwelch committed
557
558
559
560
		ret = mg_mflash_do_write_sects(buff_ptr, sect_num, 256, mg_io_cmd_write);
		if (ret != ERROR_OK)
			return ret;

561
562
563
564
565
		sect_num += 256;
		buff_ptr += 256 * MG_MFLASH_SECTOR_SIZE;
	}

	if (residue) {
duane's avatar
duane committed
566
567
		LOG_DEBUG("mflash: sect num : %" PRIu32 " buff : %p", sect_num, 
			buff_ptr);
zwelch's avatar
zwelch committed
568
		return mg_mflash_do_write_sects(buff_ptr, sect_num, residue, mg_io_cmd_write);
569
570
	}

zwelch's avatar
zwelch committed
571
	return ret;
572
573
}

574
static int mg_mflash_read (uint32_t addr, uint8_t *buff, uint32_t len)
575
{
576
577
	uint8_t *buff_ptr = buff;
	uint8_t sect_buff[MG_MFLASH_SECTOR_SIZE];
578
	uint32_t cur_addr, next_sec_addr, end_addr, cnt, sect_num;
zwelch's avatar
zwelch committed
579
	int ret = ERROR_OK;
580
581
582
583
584
585
586
587
588

	cnt = 0;
	cur_addr = addr;
	end_addr = addr + len;

	if (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK) {

		next_sec_addr = (cur_addr + MG_MFLASH_SECTOR_SIZE) & ~MG_MFLASH_SECTOR_SIZE_MASK;
		sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT;
zwelch's avatar
zwelch committed
589
590
591
		ret = mg_mflash_read_sects(sect_buff, sect_num, 1);
		if (ret != ERROR_OK)
			return ret;
592
593
594

		if (end_addr < next_sec_addr) {
			memcpy(buff_ptr, sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), end_addr - cur_addr);
duane's avatar
duane committed
595
			LOG_DEBUG("mflash: copies %" PRIu32 " byte from sector offset 0x%8.8" PRIx32 "", end_addr - cur_addr, cur_addr);
596
597
598
			cur_addr = end_addr;
		} else {
			memcpy(buff_ptr, sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), next_sec_addr - cur_addr);
duane's avatar
duane committed
599
			LOG_DEBUG("mflash: copies %" PRIu32 " byte from sector offset 0x%8.8" PRIx32 "", next_sec_addr - cur_addr, cur_addr);
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
			buff_ptr += (next_sec_addr - cur_addr);
			cur_addr = next_sec_addr;
		}
	}

	if (cur_addr < end_addr) {

		sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT;
		next_sec_addr = cur_addr + MG_MFLASH_SECTOR_SIZE;

		while (next_sec_addr <= end_addr) {
			cnt++;
			next_sec_addr += MG_MFLASH_SECTOR_SIZE;
		}

		if (cnt)
zwelch's avatar
zwelch committed
616
617
			if ((ret = mg_mflash_read_sects(buff_ptr, sect_num, cnt)) != ERROR_OK)
				return ret;
618
619
620
621
622
623
624

		buff_ptr += cnt * MG_MFLASH_SECTOR_SIZE;
		cur_addr += cnt * MG_MFLASH_SECTOR_SIZE;

		if (cur_addr < end_addr) {

			sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT;
zwelch's avatar
zwelch committed
625
626
627
628
			ret = mg_mflash_read_sects(sect_buff, sect_num, 1);
			if (ret != ERROR_OK)
				return ret;

629
			memcpy(buff_ptr, sect_buff, end_addr - cur_addr);
duane's avatar
duane committed
630
			LOG_DEBUG("mflash: copies %u byte", (unsigned)(end_addr - cur_addr));
631
632
633
634

		}
	}

zwelch's avatar
zwelch committed
635
	return ret;
636
637
}

638
static int mg_mflash_write(uint32_t addr, uint8_t *buff, uint32_t len)
639
{
640
641
	uint8_t *buff_ptr = buff;
	uint8_t sect_buff[MG_MFLASH_SECTOR_SIZE];
642
	uint32_t cur_addr, next_sec_addr, end_addr, cnt, sect_num;
zwelch's avatar
zwelch committed
643
	int ret = ERROR_OK;
644
645
646
647
648
649
650
651
652

	cnt = 0;
	cur_addr = addr;
	end_addr = addr + len;

	if (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK) {

		next_sec_addr = (cur_addr + MG_MFLASH_SECTOR_SIZE) & ~MG_MFLASH_SECTOR_SIZE_MASK;
		sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT;
zwelch's avatar
zwelch committed
653
654
655
		ret = mg_mflash_read_sects(sect_buff, sect_num, 1);
		if (ret != ERROR_OK)
			return ret;
656
657
658

		if (end_addr < next_sec_addr) {
			memcpy(sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), buff_ptr, end_addr - cur_addr);
duane's avatar
duane committed
659
			LOG_DEBUG("mflash: copies %" PRIu32 " byte to sector offset 0x%8.8" PRIx32 "", end_addr - cur_addr, cur_addr);
660
661
662
			cur_addr = end_addr;
		} else {
			memcpy(sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), buff_ptr, next_sec_addr - cur_addr);
duane's avatar
duane committed
663
			LOG_DEBUG("mflash: copies %" PRIu32 " byte to sector offset 0x%8.8" PRIx32 "", next_sec_addr - cur_addr, cur_addr);
664
665
666
667
			buff_ptr += (next_sec_addr - cur_addr);
			cur_addr = next_sec_addr;
		}

zwelch's avatar
zwelch committed
668
669
670
		ret = mg_mflash_write_sects(sect_buff, sect_num, 1);
		if (ret != ERROR_OK)
			return ret;
671
672
673
674
675
676
677
678
679
680
681
682
683
	}

	if (cur_addr < end_addr) {

		sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT;
		next_sec_addr = cur_addr + MG_MFLASH_SECTOR_SIZE;

		while (next_sec_addr <= end_addr) {
			cnt++;
			next_sec_addr += MG_MFLASH_SECTOR_SIZE;
		}

		if (cnt)
zwelch's avatar
zwelch committed
684
685
			if ((ret = mg_mflash_write_sects(buff_ptr, sect_num, cnt)) != ERROR_OK)
				return ret;
686
687
688
689
690
691
692

		buff_ptr += cnt * MG_MFLASH_SECTOR_SIZE;
		cur_addr += cnt * MG_MFLASH_SECTOR_SIZE;

		if (cur_addr < end_addr) {

			sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT;
zwelch's avatar
zwelch committed
693
694
695
696
			ret = mg_mflash_read_sects(sect_buff, sect_num, 1);
			if (ret != ERROR_OK)
				return ret;

697
			memcpy(sect_buff, buff_ptr, end_addr - cur_addr);
duane's avatar
duane committed
698
			LOG_DEBUG("mflash: copies %" PRIu32 " byte", end_addr - cur_addr);
zwelch's avatar
zwelch committed
699
			ret = mg_mflash_write_sects(sect_buff, sect_num, 1);
700
701
702
		}
	}

zwelch's avatar
zwelch committed
703
	return ret;
704
705
}

zwelch's avatar
zwelch committed
706
static int mg_write_cmd(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
707
{
708
	uint32_t address, buf_cnt, cnt, res, i;
709
	uint8_t *buffer;
710
711
712
	fileio_t fileio;
	duration_t duration;
	char *duration_text;
zwelch's avatar
zwelch committed
713
	int ret;
714
715
716
717
718
719
720

	if (argc != 3) {
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	address = strtoul(args[2], NULL, 0);

zwelch's avatar
zwelch committed
721
722
723
	ret = fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY);
	if (ret != ERROR_OK)
		return ret;
724

zwelch's avatar
zwelch committed
725
726
	buffer = malloc(MG_FILEIO_CHUNK);
	if (!buffer) {
727
728
729
730
		fileio_close(&fileio);
		return ERROR_FAIL;
	}

zwelch's avatar
zwelch committed
731
732
733
	cnt = fileio.size / MG_FILEIO_CHUNK;
	res = fileio.size % MG_FILEIO_CHUNK;

734
735
	duration_start_measure(&duration);

zwelch's avatar
zwelch committed
736
	for (i = 0; i < cnt; i++) {
zwelch's avatar
zwelch committed
737
		if ((ret = fileio_read(&fileio, MG_FILEIO_CHUNK, buffer, &buf_cnt)) !=
zwelch's avatar
zwelch committed
738
739
				ERROR_OK)
			goto mg_write_cmd_err;
zwelch's avatar
zwelch committed
740
		if ((ret = mg_mflash_write(address, buffer, MG_FILEIO_CHUNK)) != ERROR_OK)
zwelch's avatar
zwelch committed
741
742
743
744
745
			goto mg_write_cmd_err;
		address += MG_FILEIO_CHUNK;
	}
 
	if (res) {
zwelch's avatar
zwelch committed
746
		if ((ret = fileio_read(&fileio, res, buffer, &buf_cnt)) != ERROR_OK)
zwelch's avatar
zwelch committed
747
			goto mg_write_cmd_err;			
zwelch's avatar
zwelch committed
748
		if ((ret = mg_mflash_write(address, buffer, res)) != ERROR_OK)
zwelch's avatar
zwelch committed
749
750
			goto mg_write_cmd_err;
	}
751
752
753
754
755
756
757
758
759

	duration_stop_measure(&duration, &duration_text);

	command_print(cmd_ctx, "wrote %lli byte from file %s in %s (%f kB/s)",
		fileio.size, args[1], duration_text,
		(float)fileio.size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));

	free(duration_text);
	free(buffer);
zwelch's avatar
zwelch committed
760
	fileio_close(&fileio);
761
762

	return ERROR_OK;
zwelch's avatar
zwelch committed
763
764
765
766
767
768
769

mg_write_cmd_err:
	duration_stop_measure(&duration, &duration_text);
	free(duration_text);
 	free(buffer);
	fileio_close(&fileio);

zwelch's avatar
zwelch committed
770
	return ret;
771
772
}

zwelch's avatar
zwelch committed
773
static int mg_dump_cmd(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
774
{
775
	uint32_t address, size_written, size, cnt, res, i;
776
	uint8_t *buffer;
777
778
779
	fileio_t fileio;
	duration_t duration;
	char *duration_text;
zwelch's avatar
zwelch committed
780
	int ret;
781
782
783
784
785
786
787
788

	if (argc != 4) {
		return ERROR_COMMAND_SYNTAX_ERROR;
	}

	address = strtoul(args[2], NULL, 0);
	size = strtoul(args[3], NULL, 0);

zwelch's avatar
zwelch committed
789
790
791
	ret = fileio_open(&fileio, args[1], FILEIO_WRITE, FILEIO_BINARY);
	if (ret != ERROR_OK)
		return ret;
zwelch's avatar
zwelch committed
792
793
794
795
796
797
 
	buffer = malloc(MG_FILEIO_CHUNK);
	if (!buffer) {
		fileio_close(&fileio);
		return ERROR_FAIL;
	}
798

zwelch's avatar
zwelch committed
799
800
801
	cnt = size / MG_FILEIO_CHUNK;
	res = size % MG_FILEIO_CHUNK;
 
802
803
	duration_start_measure(&duration);

zwelch's avatar
zwelch committed
804
	for (i = 0; i < cnt; i++) {
zwelch's avatar
zwelch committed
805
		if ((ret = mg_mflash_read(address, buffer, MG_FILEIO_CHUNK)) != ERROR_OK)
zwelch's avatar
zwelch committed
806
			goto mg_dump_cmd_err;
zwelch's avatar
zwelch committed
807
		if ((ret = fileio_write(&fileio, MG_FILEIO_CHUNK, buffer, &size_written))
zwelch's avatar
zwelch committed
808
809
810
811
812
813
				!= ERROR_OK)
			goto mg_dump_cmd_err;
		address += MG_FILEIO_CHUNK;
	}
 
	if (res) {
zwelch's avatar
zwelch committed
814
		if ((ret = mg_mflash_read(address, buffer, res)) != ERROR_OK)
zwelch's avatar
zwelch committed
815
			goto mg_dump_cmd_err;
zwelch's avatar
zwelch committed
816
		if ((ret = fileio_write(&fileio, res, buffer, &size_written)) != ERROR_OK)
zwelch's avatar
zwelch committed
817
818
			goto mg_dump_cmd_err;
	}
819
820
821

	duration_stop_measure(&duration, &duration_text);

duane's avatar
duane committed
822
	command_print(cmd_ctx, "dump image (address 0x%8.8" PRIx32 " size %" PRIu32 ") to file %s in %s (%f kB/s)",
823
824
825
826
827
				address, size, args[1], duration_text,
				(float)size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));

	free(duration_text);
	free(buffer);
zwelch's avatar
zwelch committed
828
	fileio_close(&fileio);
829
830
831

	return ERROR_OK;

zwelch's avatar
zwelch committed
832
833
834
835
836
837
mg_dump_cmd_err:
	duration_stop_measure(&duration, &duration_text);
	free(duration_text);
 	free(buffer);
	fileio_close(&fileio);
 
zwelch's avatar
zwelch committed
838
	return ret;	
zwelch's avatar
zwelch committed
839
}
zwelch's avatar
zwelch committed
840
841
842
843

static int mg_set_feature(mg_feature_id feature, mg_feature_val config)
{
	target_t *target = mflash_bank->target;
844
	uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET;
zwelch's avatar
zwelch committed
845
	int ret;
zwelch's avatar
zwelch committed
846

zwelch's avatar
zwelch committed
847
	if ((ret = mg_dsk_wait(mg_io_wait_rdy_noerr, MG_OEM_DISK_WAIT_TIME_NORMAL))
zwelch's avatar
zwelch committed
848
			!= ERROR_OK)
zwelch's avatar
zwelch committed
849
		return ret;
zwelch's avatar
zwelch committed
850

zwelch's avatar
zwelch committed
851
852
853
	ret = target_write_u8(target, mg_task_reg + MG_REG_FEATURE, feature);
	ret |= target_write_u8(target, mg_task_reg + MG_REG_SECT_CNT, config);
	ret |= target_write_u8(target, mg_task_reg + MG_REG_COMMAND,
zwelch's avatar
zwelch committed
854
855
			mg_io_cmd_set_feature);

zwelch's avatar
zwelch committed
856
	return ret;
zwelch's avatar
zwelch committed
857
858
859
860
861
862
863
864
}

static int mg_is_valid_pll(double XIN, int N, double CLK_OUT, int NO)
{
	double v1 = XIN / N;
	double v2 = CLK_OUT * NO;

	if (v1 <1000000 || v1 > 15000000 || v2 < 100000000 || v2 > 500000000)
zwelch's avatar
zwelch committed
865
		return ERROR_MG_INVALID_PLL;
zwelch's avatar
zwelch committed
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894

	return ERROR_OK;
}

static int mg_pll_get_M(unsigned short feedback_div)
{
	int i, M;

	for (i = 1, M=0; i < 512; i <<= 1, feedback_div >>= 1)
		M += (feedback_div & 1) * i;

	return M + 2;
}

static int mg_pll_get_N(unsigned char input_div)
{
	int i, N;

	for (i = 1, N = 0; i < 32; i <<= 1, input_div >>= 1)
		N += (input_div & 1) * i;

	return N + 2;
}

static int mg_pll_get_NO(unsigned char  output_div)
{
	int i, NO;

	for (i = 0, NO = 1; i < 2; ++i, output_div >>= 1)
zwelch's avatar
zwelch committed
895
		if (output_div & 1)
zwelch's avatar
zwelch committed
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
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
955
956
957
958
			NO = NO << 1;

	return NO;
}

static double mg_do_calc_pll(double XIN, mg_pll_t * p_pll_val, int is_approximate)
{
	unsigned short i;
	unsigned char  j, k;
	int            M, N, NO;
	double CLK_OUT;
	double DIV = 1;
	double ROUND = 0;

	if (is_approximate) {
		DIV   = 1000000;
		ROUND = 500000;
	}

	for (i = 0; i < MG_PLL_MAX_FEEDBACKDIV_VAL ; ++i) {
		M  = mg_pll_get_M(i);

		for (j = 0; j < MG_PLL_MAX_INPUTDIV_VAL ; ++j) {
			N  = mg_pll_get_N(j);

			for (k = 0; k < MG_PLL_MAX_OUTPUTDIV_VAL ; ++k) {
				NO = mg_pll_get_NO(k);

				CLK_OUT = XIN * ((double)M / N) / NO;

				if ((int)((CLK_OUT+ROUND) / DIV)
						== (int)(MG_PLL_CLK_OUT / DIV))	{
					if (mg_is_valid_pll(XIN, N, CLK_OUT, NO) == ERROR_OK)
					{
						p_pll_val->lock_cyc = (int)(XIN * MG_PLL_STD_LOCKCYCLE / MG_PLL_STD_INPUTCLK);
						p_pll_val->feedback_div = i;
						p_pll_val->input_div = j;
						p_pll_val->output_div = k;

						return CLK_OUT;
					}
				}
			}
		}
	}

	return 0;
}

static double mg_calc_pll(double XIN, mg_pll_t *p_pll_val)
{
	double CLK_OUT;

	CLK_OUT = mg_do_calc_pll(XIN, p_pll_val, 0);

	if (!CLK_OUT)
		return mg_do_calc_pll(XIN, p_pll_val, 1);
	else
		return CLK_OUT;
}

static int mg_verify_interface(void)
{
zwelch's avatar
zwelch committed
959
960
	uint16_t buff[MG_MFLASH_SECTOR_SIZE >> 1];
	uint16_t i, j;
961
	uint32_t address = mflash_bank->base + MG_BUFFER_OFFSET;
zwelch's avatar
zwelch committed
962
	target_t *target = mflash_bank->target;
zwelch's avatar
zwelch committed
963
	int ret;
zwelch's avatar
zwelch committed
964
965
966
967
968

	for (j = 0; j < 10; j++) {
		for (i = 0; i < MG_MFLASH_SECTOR_SIZE >> 1; i++)
			buff[i] = i;

zwelch's avatar
zwelch committed
969
		ret = target_write_memory(target, address, 2,
970
				MG_MFLASH_SECTOR_SIZE / 2, (uint8_t *)buff);
zwelch's avatar
zwelch committed
971
972
		if (ret != ERROR_OK)
			return ret;
zwelch's avatar
zwelch committed
973
974
975

		memset(buff, 0xff, MG_MFLASH_SECTOR_SIZE);

zwelch's avatar
zwelch committed
976
		ret = target_read_memory(target, address, 2,
977
				MG_MFLASH_SECTOR_SIZE / 2, (uint8_t *)buff);
zwelch's avatar
zwelch committed
978
979
		if (ret != ERROR_OK)
			return ret;
zwelch's avatar
zwelch committed
980
981
982
983

		for (i = 0; i < MG_MFLASH_SECTOR_SIZE >> 1; i++) {
			if (buff[i] != i) {
				LOG_ERROR("mflash: verify interface fail");
zwelch's avatar
zwelch committed
984
				return ERROR_MG_INTERFACE;
zwelch's avatar
zwelch committed
985
986
987
988
989
			}
		}
	}

	LOG_INFO("mflash: verify interface ok");
zwelch's avatar
zwelch committed
990
	return ret;
zwelch's avatar
zwelch committed
991
992
993
994
995
996
997
998
999
1000
}

static const char g_strSEG_SerialNum[20] = {
	'G','m','n','i','-','e','e','S','g','a','e','l',
	0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20
};

static const char g_strSEG_FWRev[8] = {
	'F','X','L','T','2','v','0','.'
};
For faster browsing, not all history is shown. View entire blame