jedec.c 7.59 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
 */

Ronald G. Minnich's avatar
Ronald G. Minnich committed
24
#include <stdio.h>
25
#include <stdint.h>
26 27
#include "flash.h"

28 29
#define MAX_REFLASH_TRIES 0x10

30 31 32 33 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 69 70 71 72 73 74 75 76 77 78 79 80 81
void toggle_ready_jedec(volatile uint8_t *dst)
{
	unsigned int i = 0;
	uint8_t tmp1, tmp2;

	tmp1 = *dst & 0x40;

	while (i++ < 0xFFFFFFF) {
		tmp2 = *dst & 0x40;
		if (tmp1 == tmp2) {
			break;
		}
		tmp1 = tmp2;
	}
}

void data_polling_jedec(volatile uint8_t *dst, uint8_t data)
{
	unsigned int i = 0;
	uint8_t tmp;

	data &= 0x80;

	while (i++ < 0xFFFFFFF) {
		tmp = *dst & 0x80;
		if (tmp == data) {
			break;
		}
	}
}

void unprotect_jedec(volatile uint8_t *bios)
{
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
	*(volatile uint8_t *)(bios + 0x5555) = 0x80;
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
	*(volatile uint8_t *)(bios + 0x5555) = 0x20;

	usleep(200);
}

void protect_jedec(volatile uint8_t *bios)
{
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
	*(volatile uint8_t *)(bios + 0x5555) = 0xA0;

	usleep(200);
}

82
int probe_jedec(struct flashchip *flash)
83
{
84
	volatile uint8_t *bios = flash->virtual_memory;
85
	uint8_t id1, id2;
86
	uint32_t largeid1, largeid2;
87 88

	/* Issue JEDEC Product ID Entry command */
89
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
90
	myusec_delay(10);
91
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
92
	myusec_delay(10);
93
	*(volatile uint8_t *)(bios + 0x5555) = 0x90;
94 95 96 97 98
	/* Older chips may need up to 100 us to respond. The ATMEL 29C020
	 * needs 10 ms according to the data sheet, but it has been tested
	 * to work reliably with 20 us. Allow a factor of 2 safety margin.
	 */
	myusec_delay(40);
99 100

	/* Read product ID */
101 102
	id1 = *(volatile uint8_t *)bios;
	id2 = *(volatile uint8_t *)(bios + 0x01);
103 104 105 106 107 108 109 110 111 112 113 114 115 116
	largeid1 = id1;
	largeid2 = id2;

	/* Check if it is a continuation ID, this should be a while loop. */
	if (id1 == 0x7F) {
		largeid1 <<= 8;
		id1 = *(volatile uint8_t *)(bios + 0x100);
		largeid1 |= id1;
	}
	if (id2 == 0x7F) {
		largeid2 <<= 8;
		id2 = *(volatile uint8_t *)(bios + 0x101);
		largeid2 |= id2;
	}
117 118

	/* Issue JEDEC Product ID Exit command */
119
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
120
	myusec_delay(10);
121
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
122
	myusec_delay(10);
123
	*(volatile uint8_t *)(bios + 0x5555) = 0xF0;
124
	myusec_delay(40);
125

126 127
	printf_debug("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, largeid1, largeid2);
	if (largeid1 == flash->manufacture_id && largeid2 == flash->model_id)
128
		return 1;
129

130
	return 0;
Ollie Lho's avatar
Ollie Lho committed
131
}
132

133
int erase_sector_jedec(volatile uint8_t *bios, unsigned int page)
Ollie Lho's avatar
Ollie Lho committed
134
{
135
	/*  Issue the Sector Erase command   */
136
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
137
	myusec_delay(10);
138
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
139
	myusec_delay(10);
140
	*(volatile uint8_t *)(bios + 0x5555) = 0x80;
Ollie Lho's avatar
Ollie Lho committed
141
	myusec_delay(10);
142

143
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
Ollie Lho's avatar
Ollie Lho committed
144
	myusec_delay(10);
145
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
Ollie Lho's avatar
Ollie Lho committed
146
	myusec_delay(10);
147
	*(volatile uint8_t *)(bios + page) = 0x30;
Ollie Lho's avatar
Ollie Lho committed
148
	myusec_delay(10);
149 150 151 152

	/* wait for Toggle bit ready         */
	toggle_ready_jedec(bios);

Uwe Hermann's avatar
Uwe Hermann committed
153
	return 0;
154
}
155

156
int erase_block_jedec(volatile uint8_t *bios, unsigned int block)
157 158
{
	/*  Issue the Sector Erase command   */
159
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
160
	myusec_delay(10);
161
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
162
	myusec_delay(10);
163
	*(volatile uint8_t *)(bios + 0x5555) = 0x80;
164
	myusec_delay(10);
165

166
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
167
	myusec_delay(10);
168
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
169
	myusec_delay(10);
170
	*(volatile uint8_t *)(bios + block) = 0x50;
171
	myusec_delay(10);
172

Ollie Lho's avatar
Ollie Lho committed
173 174
	/* wait for Toggle bit ready         */
	toggle_ready_jedec(bios);
175

Uwe Hermann's avatar
Uwe Hermann committed
176
	return 0;
177 178
}

179
int erase_chip_jedec(struct flashchip *flash)
180
{
181
	volatile uint8_t *bios = flash->virtual_memory;
182

183
	/*  Issue the JEDEC Chip Erase command   */
184
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
Ollie Lho's avatar
Ollie Lho committed
185
	myusec_delay(10);
186
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
187
	myusec_delay(10);
188
	*(volatile uint8_t *)(bios + 0x5555) = 0x80;
Ollie Lho's avatar
Ollie Lho committed
189
	myusec_delay(10);
190

191
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
Ollie Lho's avatar
Ollie Lho committed
192
	myusec_delay(10);
193
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
Ollie Lho's avatar
Ollie Lho committed
194
	myusec_delay(10);
195
	*(volatile uint8_t *)(bios + 0x5555) = 0x10;
Ollie Lho's avatar
Ollie Lho committed
196 197
	myusec_delay(10);

198
	toggle_ready_jedec(bios);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
199

Uwe Hermann's avatar
Uwe Hermann committed
200
	return 0;
201 202
}

203 204
int write_page_write_jedec(volatile uint8_t *bios, uint8_t *src,
			   volatile uint8_t *dst, int page_size)
205
{
206 207 208
	int i, tried = 0, start_index = 0, ok;
	volatile uint8_t *d = dst;
	uint8_t *s = src;
209

210
retry:
211
	/* Issue JEDEC Data Unprotect comand */
212 213 214
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
	*(volatile uint8_t *)(bios + 0x5555) = 0xA0;
215

216
	/* transfer data from source to destination */
217
	for (i = start_index; i < page_size; i++) {
218
		/* If the data is 0xFF, don't program it */
219
		if (*src != 0xFF)
220 221 222
			*dst = *src;
		dst++;
		src++;
223 224 225
	}

	toggle_ready_jedec(dst - 1);
226

227 228 229 230
	dst = d;
	src = s;
	ok = 1;
	for (i = 0; i < page_size; i++) {
231
		if (*dst != *src) {
232 233 234 235 236 237
			ok = 0;
			break;
		}
		dst++;
		src++;
	}
238

239 240
	if (!ok && tried++ < MAX_REFLASH_TRIES) {
		start_index = i;
241 242
		goto retry;
	}
243
	if (!ok) {
244 245
		fprintf(stderr, " page %d failed!\n",
			(unsigned int)(d - bios) / page_size);
246
	}
Uwe Hermann's avatar
Uwe Hermann committed
247
	return !ok;
248 249
}

250 251
int write_byte_program_jedec(volatile uint8_t *bios, uint8_t *src,
			     volatile uint8_t *dst)
Ollie Lho's avatar
Ollie Lho committed
252
{
253
	int tried = 0, ok = 1;
254

255
	/* If the data is 0xFF, don't program it */
Ollie Lho's avatar
Ollie Lho committed
256
	if (*src == 0xFF) {
257
		return -1;
Ollie Lho's avatar
Ollie Lho committed
258
	}
259

260
retry:
Ollie Lho's avatar
Ollie Lho committed
261
	/* Issue JEDEC Byte Program command */
262 263 264
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
	*(volatile uint8_t *)(bios + 0x5555) = 0xA0;
265 266

	/* transfer data from source to destination */
Ollie Lho's avatar
Ollie Lho committed
267 268
	*dst = *src;
	toggle_ready_jedec(bios);
269

270
	if (*dst != *src && tried++ < MAX_REFLASH_TRIES) {
271 272
		goto retry;
	}
273

274
	if (tried >= MAX_REFLASH_TRIES)
275
		ok = 0;
276

Uwe Hermann's avatar
Uwe Hermann committed
277
	return !ok;
Ollie Lho's avatar
Ollie Lho committed
278 279
}

280 281
int write_sector_jedec(volatile uint8_t *bios, uint8_t *src,
		       volatile uint8_t *dst, unsigned int page_size)
282 283 284 285
{
	int i;

	for (i = 0; i < page_size; i++) {
286 287
		write_byte_program_jedec(bios, src, dst);
		dst++, src++;
288 289
	}

Uwe Hermann's avatar
Uwe Hermann committed
290
	return 0;
291 292
}

293
int write_jedec(struct flashchip *flash, uint8_t *buf)
294 295
{
	int i;
Ollie Lho's avatar
Ollie Lho committed
296 297
	int total_size = flash->total_size * 1024;
	int page_size = flash->page_size;
298
	volatile uint8_t *bios = flash->virtual_memory;
299

300
	erase_chip_jedec(flash);
301 302 303
	// dumb check if erase was successful.
	for (i = 0; i < total_size; i++) {
		if (bios[i] != (uint8_t) 0xff) {
304
			printf("ERASE FAILED @%d, val %02x!\n", i, bios[i]);
305 306 307
			return -1;
		}
	}
308

309
	printf("Programming page: ");
310 311
	for (i = 0; i < total_size / page_size; i++) {
		printf("%04d at address: 0x%08x", i, i * page_size);
312 313
		write_page_write_jedec(bios, buf + i * page_size,
				       bios + i * page_size, page_size);
Ollie Lho's avatar
Ollie Lho committed
314
		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");
315 316
	}
	printf("\n");
317
	protect_jedec(bios);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
318

Uwe Hermann's avatar
Uwe Hermann committed
319
	return 0;
320
}