jedec.c 11.9 KB
Newer Older
1
/*
2
 * This file is part of the flashrom project.
3
 *
4 5 6
 * Copyright (C) 2000 Silicon Integrated System Corporation
 * Copyright (C) 2006 Giampiero Giancipoli <gianci@email.it>
 * Copyright (C) 2006 coresystems GmbH <info@coresystems.de>
7
 * Copyright (C) 2007 Carl-Daniel Hailfinger
8
 * Copyright (C) 2009 Sean Nelson <audiohacked@gmail.com>
9
 *
10 11 12 13
 * 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.
14
 *
15 16 17 18
 * 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.
19
 *
20 21 22
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
23 24 25 26
 */

#include "flash.h"

27
#define MAX_REFLASH_TRIES 0x10
28 29
#define MASK_FULL 0xffff
#define MASK_2AA 0x7ff
30

31 32 33 34 35 36 37 38
/* Check one byte for odd parity */
uint8_t oddparity(uint8_t val)
{
	val = (val ^ (val >> 4)) & 0xf;
	val = (val ^ (val >> 2)) & 0x3;
	return (val ^ (val >> 1)) & 0x1;
}

39
void toggle_ready_jedec_common(chipaddr dst, int delay)
40 41 42 43
{
	unsigned int i = 0;
	uint8_t tmp1, tmp2;

44
	tmp1 = chip_readb(dst) & 0x40;
45 46

	while (i++ < 0xFFFFFFF) {
47 48
		if (delay)
			programmer_delay(delay);
49
		tmp2 = chip_readb(dst) & 0x40;
50 51 52 53 54
		if (tmp1 == tmp2) {
			break;
		}
		tmp1 = tmp2;
	}
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
	if (i > 0x100000)
		printf_debug("%s: excessive loops, i=0x%x\n", __func__, i);
}

void toggle_ready_jedec(chipaddr dst)
{
	toggle_ready_jedec_common(dst, 0);
}

/* Some chips require a minimum delay between toggle bit reads.
 * The Winbond W39V040C wants 50 ms between reads on sector erase toggle,
 * but experiments show that 2 ms are already enough. Pick a safety factor
 * of 4 and use an 8 ms delay.
 * Given that erase is slow on all chips, it is recommended to use 
 * toggle_ready_jedec_slow in erase functions.
 */
void toggle_ready_jedec_slow(chipaddr dst)
{
	toggle_ready_jedec_common(dst, 8 * 1000);
74 75
}

76
void data_polling_jedec(chipaddr dst, uint8_t data)
77 78 79 80 81 82 83
{
	unsigned int i = 0;
	uint8_t tmp;

	data &= 0x80;

	while (i++ < 0xFFFFFFF) {
84
		tmp = chip_readb(dst) & 0x80;
85 86 87 88
		if (tmp == data) {
			break;
		}
	}
89 90
	if (i > 0x100000)
		printf_debug("%s: excessive loops, i=0x%x\n", __func__, i);
91 92
}

93
void start_program_jedec_common(struct flashchip *flash, unsigned int mask)
94
{
95 96 97 98
	chipaddr bios = flash->virtual_memory;
	chip_writeb(0xAA, bios + (0x5555 & mask));
	chip_writeb(0x55, bios + (0x2AAA & mask));
	chip_writeb(0xA0, bios + (0x5555 & mask));
99 100
}

101 102
int probe_jedec_common(struct flashchip *flash,
			unsigned int mask, int long_reset)
103
{
104
	chipaddr bios = flash->virtual_memory;
105
	uint8_t id1, id2;
106
	uint32_t largeid1, largeid2;
107
	uint32_t flashcontent1, flashcontent2;
108 109 110 111 112 113 114 115
	int probe_timing_enter, probe_timing_exit;

	if (flash->probe_timing > 0) 
		probe_timing_enter = probe_timing_exit = flash->probe_timing;
	else if (flash->probe_timing == TIMING_ZERO) { /* No delay. */
		probe_timing_enter = probe_timing_exit = 0;
	} else if (flash->probe_timing == TIMING_FIXME) { /* == _IGNORED */
		printf_debug("Chip lacks correct probe timing information, "
116
			     "using default 10mS/40uS. ");
117 118 119 120 121 122 123
		probe_timing_enter = 10000;
		probe_timing_exit = 40;
	} else {
		printf("Chip has negative value in probe_timing, failing "
		       "without chip access\n");
		return 0;
	}
124 125

	/* Issue JEDEC Product ID Entry command */
126
	chip_writeb(0xAA, bios + (0x5555 & mask));
127 128
	if (probe_timing_enter)
		programmer_delay(10);
129
	chip_writeb(0x55, bios + (0x2AAA & mask));
130 131
	if (probe_timing_enter)
		programmer_delay(10);
132
	chip_writeb(0x90, bios + (0x5555 & mask));
133 134
	if (probe_timing_enter)
		programmer_delay(probe_timing_enter);
135 136

	/* Read product ID */
137 138
	id1 = chip_readb(bios);
	id2 = chip_readb(bios + 0x01);
139 140 141 142 143 144
	largeid1 = id1;
	largeid2 = id2;

	/* Check if it is a continuation ID, this should be a while loop. */
	if (id1 == 0x7F) {
		largeid1 <<= 8;
145
		id1 = chip_readb(bios + 0x100);
146 147 148 149
		largeid1 |= id1;
	}
	if (id2 == 0x7F) {
		largeid2 <<= 8;
150
		id2 = chip_readb(bios + 0x101);
151 152
		largeid2 |= id2;
	}
153 154

	/* Issue JEDEC Product ID Exit command */
155 156 157 158 159 160 161 162 163 164
	if (long_reset)
	{
		chip_writeb(0xAA, bios + (0x5555 & mask));
		if (probe_timing_exit)
			programmer_delay(10);
		chip_writeb(0x55, bios + (0x2AAA & mask));
		if (probe_timing_exit)
			programmer_delay(10);
	}
	chip_writeb(0xF0, bios + (0x5555 & mask));
165 166
	if (probe_timing_exit)
		programmer_delay(probe_timing_exit);
167

168
	printf_debug("%s: id1 0x%02x, id2 0x%02x", __func__, largeid1, largeid2);
169 170
	if (!oddparity(id1))
		printf_debug(", id1 parity violation");
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190

	/* Read the product ID location again. We should now see normal flash contents. */
	flashcontent1 = chip_readb(bios);
	flashcontent2 = chip_readb(bios + 0x01);

	/* Check if it is a continuation ID, this should be a while loop. */
	if (flashcontent1 == 0x7F) {
		flashcontent1 <<= 8;
		flashcontent1 |= chip_readb(bios + 0x100);
	}
	if (flashcontent2 == 0x7F) {
		flashcontent2 <<= 8;
		flashcontent2 |= chip_readb(bios + 0x101);
	}

	if (largeid1 == flashcontent1)
		printf_debug(", id1 is normal flash content");
	if (largeid2 == flashcontent2)
		printf_debug(", id2 is normal flash content");

191
	printf_debug("\n");
192 193
	if (largeid1 != flash->manufacture_id || largeid2 != flash->model_id)
		return 0;
194

195 196 197
	if (flash->feature_bits & FEATURE_REGISTERMAP)
		map_flash_registers(flash);

198
	return 1;
Ollie Lho's avatar
Ollie Lho committed
199
}
200

201 202
int erase_sector_jedec_common(struct flashchip *flash, unsigned int page,
			      unsigned int pagesize, unsigned int mask)
Ollie Lho's avatar
Ollie Lho committed
203
{
204 205
	chipaddr bios = flash->virtual_memory;

206
	/*  Issue the Sector Erase command   */
207
	chip_writeb(0xAA, bios + (0x5555 & mask));
208
	programmer_delay(10);
209
	chip_writeb(0x55, bios + (0x2AAA & mask));
210
	programmer_delay(10);
211
	chip_writeb(0x80, bios + (0x5555 & mask));
212
	programmer_delay(10);
213

214
	chip_writeb(0xAA, bios + (0x5555 & mask));
215
	programmer_delay(10);
216
	chip_writeb(0x55, bios + (0x2AAA & mask));
217
	programmer_delay(10);
218
	chip_writeb(0x30, bios + page);
219
	programmer_delay(10);
220 221

	/* wait for Toggle bit ready         */
222
	toggle_ready_jedec_slow(bios);
223

224 225 226 227
	if (check_erased_range(flash, page, pagesize)) {
		fprintf(stderr,"ERASE FAILED!\n");
		return -1;
	}
Uwe Hermann's avatar
Uwe Hermann committed
228
	return 0;
229
}
230

231 232
int erase_block_jedec_common(struct flashchip *flash, unsigned int block,
			     unsigned int blocksize, unsigned int mask)
233
{
234 235
	chipaddr bios = flash->virtual_memory;

236
	/*  Issue the Sector Erase command   */
237
	chip_writeb(0xAA, bios + (0x5555 & mask));
238
	programmer_delay(10);
239
	chip_writeb(0x55, bios + (0x2AAA & mask));
240
	programmer_delay(10);
241
	chip_writeb(0x80, bios + (0x5555 & mask));
242
	programmer_delay(10);
243

244
	chip_writeb(0xAA, bios + (0x5555 & mask));
245
	programmer_delay(10);
246
	chip_writeb(0x55, bios + (0x2AAA & mask));
247
	programmer_delay(10);
248
	chip_writeb(0x50, bios + block);
249
	programmer_delay(10);
250

Ollie Lho's avatar
Ollie Lho committed
251
	/* wait for Toggle bit ready         */
252
	toggle_ready_jedec_slow(bios);
253

254 255 256 257
	if (check_erased_range(flash, block, blocksize)) {
		fprintf(stderr,"ERASE FAILED!\n");
		return -1;
	}
Uwe Hermann's avatar
Uwe Hermann committed
258
	return 0;
259 260
}

261
int erase_chip_jedec_common(struct flashchip *flash, unsigned int mask)
262
{
263
	int total_size = flash->total_size * 1024;
264
	chipaddr bios = flash->virtual_memory;
265

266
	/*  Issue the JEDEC Chip Erase command   */
267
	chip_writeb(0xAA, bios + (0x5555 & mask));
268
	programmer_delay(10);
269
	chip_writeb(0x55, bios + (0x2AAA & mask));
270
	programmer_delay(10);
271
	chip_writeb(0x80, bios + (0x5555 & mask));
272
	programmer_delay(10);
273

274
	chip_writeb(0xAA, bios + (0x5555 & mask));
275
	programmer_delay(10);
276
	chip_writeb(0x55, bios + (0x2AAA & mask));
277
	programmer_delay(10);
278
	chip_writeb(0x10, bios + (0x5555 & mask));
279
	programmer_delay(10);
Ollie Lho's avatar
Ollie Lho committed
280

281
	toggle_ready_jedec_slow(bios);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
282

283 284 285 286
	if (check_erased_range(flash, 0, total_size)) {
		fprintf(stderr,"ERASE FAILED!\n");
		return -1;
	}
Uwe Hermann's avatar
Uwe Hermann committed
287
	return 0;
288 289
}

290 291
int write_byte_program_jedec_common(struct flashchip *flash, uint8_t *src,
			     chipaddr dst, unsigned int mask)
Ollie Lho's avatar
Ollie Lho committed
292
{
293
	int tried = 0, failed = 0;
294
	chipaddr bios = flash->virtual_memory;
295

296
	/* If the data is 0xFF, don't program it and don't complain. */
Ollie Lho's avatar
Ollie Lho committed
297
	if (*src == 0xFF) {
298
		return 0;
Ollie Lho's avatar
Ollie Lho committed
299
	}
300

301
retry:
Ollie Lho's avatar
Ollie Lho committed
302
	/* Issue JEDEC Byte Program command */
303
	start_program_jedec_common(flash, mask);
304 305

	/* transfer data from source to destination */
306
	chip_writeb(*src, dst);
Ollie Lho's avatar
Ollie Lho committed
307
	toggle_ready_jedec(bios);
308

309
	if (chip_readb(dst) != *src && tried++ < MAX_REFLASH_TRIES) {
310 311
		goto retry;
	}
312

313
	if (tried >= MAX_REFLASH_TRIES)
314
		failed = 1;
315

316
	return failed;
Ollie Lho's avatar
Ollie Lho committed
317 318
}

319 320
int write_sector_jedec_common(struct flashchip *flash, uint8_t *src,
		       chipaddr dst, unsigned int page_size, unsigned int mask)
321
{
322 323
	int i, failed = 0;
	chipaddr olddst;
324

325
	olddst = dst;
326
	for (i = 0; i < page_size; i++) {
327
		if (write_byte_program_jedec_common(flash, src, dst, mask))
328
			failed = 1;
329
		dst++, src++;
330
	}
331 332
	if (failed)
		fprintf(stderr, " writing sector at 0x%lx failed!\n", olddst);
333

334
	return failed;
335 336
}

337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
int write_page_write_jedec_common(struct flashchip *flash, uint8_t *src,
			   int start, int page_size, unsigned int mask)
{
	int i, tried = 0, failed;
	uint8_t *s = src;
	chipaddr bios = flash->virtual_memory;
	chipaddr dst = bios + start;
	chipaddr d = dst;

retry:
	/* Issue JEDEC Start Program comand */
	start_program_jedec_common(flash, mask);

	/* transfer data from source to destination */
	for (i = 0; i < page_size; i++) {
		/* If the data is 0xFF, don't program it */
		if (*src != 0xFF)
			chip_writeb(*src, dst);
		dst++;
		src++;
	}

	toggle_ready_jedec(dst - 1);

	dst = d;
	src = s;
	failed = verify_range(flash, src, start, page_size, NULL);

	if (failed && tried++ < MAX_REFLASH_TRIES) {
		fprintf(stderr, "retrying.\n");
		goto retry;
	}
	if (failed) {
		fprintf(stderr, " page 0x%lx failed!\n",
			(d - bios) / page_size);
	}
	return failed;
}

376 377 378 379 380 381 382 383 384 385 386 387 388
int getaddrmask(struct flashchip *flash)
{
	switch (flash->feature_bits & FEATURE_ADDR_MASK) {
	case FEATURE_ADDR_FULL:
		return MASK_FULL;
		break;
	default:
		fprintf(stderr, "%s called with unknown mask\n", __func__);
		return 0;
		break;
	}
}

389
int write_jedec(struct flashchip *flash, uint8_t *buf)
390
{
391
	int i, failed = 0;
Ollie Lho's avatar
Ollie Lho committed
392 393
	int total_size = flash->total_size * 1024;
	int page_size = flash->page_size;
394

395 396 397
	if (erase_chip_jedec(flash)) {
		fprintf(stderr,"ERASE FAILED!\n");
		return -1;
398
	}
399
	
400
	printf("Programming page: ");
401 402
	for (i = 0; i < total_size / page_size; i++) {
		printf("%04d at address: 0x%08x", i, i * page_size);
403 404
		if (write_page_write_jedec_common(flash, buf + i * page_size,
					   i * page_size, page_size, MASK_FULL))
405
			failed = 1;
Ollie Lho's avatar
Ollie Lho committed
406
		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
407 408
	}
	printf("\n");
Ronald G. Minnich's avatar
Ronald G. Minnich committed
409

410
	return failed;
411
}
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429

int write_jedec_1(struct flashchip *flash, uint8_t * buf)
{
	int i;
	chipaddr bios = flash->virtual_memory;
	chipaddr dst = bios;

	programmer_delay(10);
	if (erase_flash(flash)) {
		fprintf(stderr, "ERASE FAILED!\n");
		return -1;
	}

	printf("Programming page: ");
	for (i = 0; i < flash->total_size; i++) {
		if ((i & 0x3) == 0)
			printf("address: 0x%08lx", (unsigned long)i * 1024);

430
                write_sector_jedec_common(flash, buf + i * 1024, dst + i * 1024, 1024, MASK_FULL);
431 432 433 434 435 436 437 438

		if ((i & 0x3) == 0)
			printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
	}

	printf("\n");
	return 0;
}
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453

/* erase chip with block_erase() prototype */
int erase_chip_block_jedec(struct flashchip *flash, unsigned int addr,
			   unsigned int blocksize)
{
	if ((addr != 0) || (blocksize != flash->total_size * 1024)) {
		fprintf(stderr, "%s called with incorrect arguments\n",
			__func__);
		return -1;
	}
	return erase_chip_jedec_common(flash, MASK_FULL);
}

int probe_jedec(struct flashchip *flash)
{
454 455 456 457
	int mask;

	mask = getaddrmask(flash);
	return probe_jedec_common(flash, mask, 1);
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
}

int erase_sector_jedec(struct flashchip *flash, unsigned int page, unsigned int size)
{
	return erase_sector_jedec_common(flash, page, size, MASK_FULL);
}

int erase_block_jedec(struct flashchip *flash, unsigned int page, unsigned int size)
{
	return erase_block_jedec_common(flash, page, size, MASK_FULL);
}

int erase_chip_jedec(struct flashchip *flash)
{
	return erase_chip_jedec_common(flash, MASK_FULL);
}