jedec.c 10.3 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
 *
9 10 11 12
 * 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.
13
 *
14 15 16 17
 * 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.
18
 *
19 20 21
 * 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
22 23 24 25
 */

#include "flash.h"

26 27
#define MAX_REFLASH_TRIES 0x10

28 29 30 31 32 33 34 35
/* 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;
}

36
void toggle_ready_jedec_common(chipaddr dst, int delay)
37 38 39 40
{
	unsigned int i = 0;
	uint8_t tmp1, tmp2;

41
	tmp1 = chip_readb(dst) & 0x40;
42 43

	while (i++ < 0xFFFFFFF) {
44 45
		if (delay)
			programmer_delay(delay);
46
		tmp2 = chip_readb(dst) & 0x40;
47 48 49 50 51
		if (tmp1 == tmp2) {
			break;
		}
		tmp1 = tmp2;
	}
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
	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);
71 72
}

73
void data_polling_jedec(chipaddr dst, uint8_t data)
74 75 76 77 78 79 80
{
	unsigned int i = 0;
	uint8_t tmp;

	data &= 0x80;

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

90
void start_program_jedec(chipaddr bios)
91
{
92 93 94
	chip_writeb(0xAA, bios + 0x5555);
	chip_writeb(0x55, bios + 0x2AAA);
	chip_writeb(0xA0, bios + 0x5555);
95 96
}

97
int probe_jedec(struct flashchip *flash)
98
{
99
	chipaddr bios = flash->virtual_memory;
100
	uint8_t id1, id2;
101
	uint32_t largeid1, largeid2;
102
	uint32_t flashcontent1, flashcontent2;
103 104 105 106 107 108 109 110
	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, "
111
			     "using default 10mS/40uS. ");
112 113 114 115 116 117 118
		probe_timing_enter = 10000;
		probe_timing_exit = 40;
	} else {
		printf("Chip has negative value in probe_timing, failing "
		       "without chip access\n");
		return 0;
	}
119 120

	/* Issue JEDEC Product ID Entry command */
121
	chip_writeb(0xAA, bios + 0x5555);
122 123
	if (probe_timing_enter)
		programmer_delay(10);
124
	chip_writeb(0x55, bios + 0x2AAA);
125 126
	if (probe_timing_enter)
		programmer_delay(10);
127
	chip_writeb(0x90, bios + 0x5555);
128 129
	if (probe_timing_enter)
		programmer_delay(probe_timing_enter);
130 131

	/* Read product ID */
132 133
	id1 = chip_readb(bios);
	id2 = chip_readb(bios + 0x01);
134 135 136 137 138 139
	largeid1 = id1;
	largeid2 = id2;

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

	/* Issue JEDEC Product ID Exit command */
150
	chip_writeb(0xAA, bios + 0x5555);
151 152
	if (probe_timing_exit)
		programmer_delay(10);
153
	chip_writeb(0x55, bios + 0x2AAA);
154 155
	if (probe_timing_exit)
		programmer_delay(10);
156
	chip_writeb(0xF0, bios + 0x5555);
157 158
	if (probe_timing_exit)
		programmer_delay(probe_timing_exit);
159

160
	printf_debug("%s: id1 0x%02x, id2 0x%02x", __func__, largeid1, largeid2);
161 162
	if (!oddparity(id1))
		printf_debug(", id1 parity violation");
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182

	/* 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");

183
	printf_debug("\n");
184
	if (largeid1 == flash->manufacture_id && largeid2 == flash->model_id)
185
		return 1;
186

187
	return 0;
Ollie Lho's avatar
Ollie Lho committed
188
}
189

190
int erase_sector_jedec(struct flashchip *flash, unsigned int page, unsigned int pagesize)
Ollie Lho's avatar
Ollie Lho committed
191
{
192 193
	chipaddr bios = flash->virtual_memory;

194
	/*  Issue the Sector Erase command   */
195
	chip_writeb(0xAA, bios + 0x5555);
196
	programmer_delay(10);
197
	chip_writeb(0x55, bios + 0x2AAA);
198
	programmer_delay(10);
199
	chip_writeb(0x80, bios + 0x5555);
200
	programmer_delay(10);
201

202
	chip_writeb(0xAA, bios + 0x5555);
203
	programmer_delay(10);
204
	chip_writeb(0x55, bios + 0x2AAA);
205
	programmer_delay(10);
206
	chip_writeb(0x30, bios + page);
207
	programmer_delay(10);
208 209

	/* wait for Toggle bit ready         */
210
	toggle_ready_jedec_slow(bios);
211

212 213 214 215
	if (check_erased_range(flash, page, pagesize)) {
		fprintf(stderr,"ERASE FAILED!\n");
		return -1;
	}
Uwe Hermann's avatar
Uwe Hermann committed
216
	return 0;
217
}
218

219
int erase_block_jedec(struct flashchip *flash, unsigned int block, unsigned int blocksize)
220
{
221 222
	chipaddr bios = flash->virtual_memory;

223
	/*  Issue the Sector Erase command   */
224
	chip_writeb(0xAA, bios + 0x5555);
225
	programmer_delay(10);
226
	chip_writeb(0x55, bios + 0x2AAA);
227
	programmer_delay(10);
228
	chip_writeb(0x80, bios + 0x5555);
229
	programmer_delay(10);
230

231
	chip_writeb(0xAA, bios + 0x5555);
232
	programmer_delay(10);
233
	chip_writeb(0x55, bios + 0x2AAA);
234
	programmer_delay(10);
235
	chip_writeb(0x50, bios + block);
236
	programmer_delay(10);
237

Ollie Lho's avatar
Ollie Lho committed
238
	/* wait for Toggle bit ready         */
239
	toggle_ready_jedec_slow(bios);
240

241 242 243 244
	if (check_erased_range(flash, block, blocksize)) {
		fprintf(stderr,"ERASE FAILED!\n");
		return -1;
	}
Uwe Hermann's avatar
Uwe Hermann committed
245
	return 0;
246 247
}

248 249 250 251 252 253 254 255 256 257 258
/* 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(flash);
}

259
int erase_chip_jedec(struct flashchip *flash)
260
{
261
	int total_size = flash->total_size * 1024;
262
	chipaddr bios = flash->virtual_memory;
263

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

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

279
	toggle_ready_jedec_slow(bios);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
280

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

288 289
int write_page_write_jedec(struct flashchip *flash, uint8_t *src,
			   int start, int page_size)
290
{
291
	int i, tried = 0, failed;
292
	uint8_t *s = src;
293 294 295
	chipaddr bios = flash->virtual_memory;
	chipaddr dst = bios + start;
	chipaddr d = dst;
296

297
retry:
298
	/* Issue JEDEC Data Unprotect comand */
299
	start_program_jedec(bios);
300

301
	/* transfer data from source to destination */
302
	for (i = 0; i < page_size; i++) {
303
		/* If the data is 0xFF, don't program it */
304
		if (*src != 0xFF)
305
			chip_writeb(*src, dst);
306 307
		dst++;
		src++;
308 309 310
	}

	toggle_ready_jedec(dst - 1);
311

312 313
	dst = d;
	src = s;
314
	failed = verify_range(flash, src, start, page_size, NULL);
315

316
	if (failed && tried++ < MAX_REFLASH_TRIES) {
317
		fprintf(stderr, "retrying.\n");
318 319
		goto retry;
	}
320
	if (failed) {
321 322
		fprintf(stderr, " page 0x%lx failed!\n",
			(d - bios) / page_size);
323
	}
324
	return failed;
325 326
}

327 328
int write_byte_program_jedec(chipaddr bios, uint8_t *src,
			     chipaddr dst)
Ollie Lho's avatar
Ollie Lho committed
329
{
330
	int tried = 0, failed = 0;
331

332
	/* If the data is 0xFF, don't program it and don't complain. */
Ollie Lho's avatar
Ollie Lho committed
333
	if (*src == 0xFF) {
334
		return 0;
Ollie Lho's avatar
Ollie Lho committed
335
	}
336

337
retry:
Ollie Lho's avatar
Ollie Lho committed
338
	/* Issue JEDEC Byte Program command */
339
	start_program_jedec(bios);
340 341

	/* transfer data from source to destination */
342
	chip_writeb(*src, dst);
Ollie Lho's avatar
Ollie Lho committed
343
	toggle_ready_jedec(bios);
344

345
	if (chip_readb(dst) != *src && tried++ < MAX_REFLASH_TRIES) {
346 347
		goto retry;
	}
348

349
	if (tried >= MAX_REFLASH_TRIES)
350
		failed = 1;
351

352
	return failed;
Ollie Lho's avatar
Ollie Lho committed
353 354
}

355 356
int write_sector_jedec(chipaddr bios, uint8_t *src,
		       chipaddr dst, unsigned int page_size)
357
{
358 359
	int i, failed = 0;
	chipaddr olddst;
360

361
	olddst = dst;
362
	for (i = 0; i < page_size; i++) {
363 364
		if (write_byte_program_jedec(bios, src, dst))
			failed = 1;
365
		dst++, src++;
366
	}
367 368
	if (failed)
		fprintf(stderr, " writing sector at 0x%lx failed!\n", olddst);
369

370
	return failed;
371 372
}

373
int write_jedec(struct flashchip *flash, uint8_t *buf)
374
{
375
	int i, failed = 0;
Ollie Lho's avatar
Ollie Lho committed
376 377
	int total_size = flash->total_size * 1024;
	int page_size = flash->page_size;
378

379 380 381
	if (erase_chip_jedec(flash)) {
		fprintf(stderr,"ERASE FAILED!\n");
		return -1;
382
	}
383
	
384
	printf("Programming page: ");
385 386
	for (i = 0; i < total_size / page_size; i++) {
		printf("%04d at address: 0x%08x", i, i * page_size);
387 388 389
		if (write_page_write_jedec(flash, buf + i * page_size,
					   i * page_size, page_size))
			failed = 1;
Ollie Lho's avatar
Ollie Lho committed
390
		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");
391 392
	}
	printf("\n");
Ronald G. Minnich's avatar
Ronald G. Minnich committed
393

394
	return failed;
395
}
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422

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);

                write_sector_jedec(bios, buf + i * 1024, dst + i * 1024, 1024);

		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;
}