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

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

27 28
#define MAX_REFLASH_TRIES 0x10

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

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

	/* Issue JEDEC Product ID Entry command */
87
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
88
	myusec_delay(10);
89
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
90
	myusec_delay(10);
91
	*(volatile uint8_t *)(bios + 0x5555) = 0x90;
92 93 94 95 96
	/* 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);
97 98

	/* Read product ID */
99 100
	id1 = *(volatile uint8_t *)bios;
	id2 = *(volatile uint8_t *)(bios + 0x01);
101 102

	/* Issue JEDEC Product ID Exit command */
103
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
104
	myusec_delay(10);
105
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
106
	myusec_delay(10);
107
	*(volatile uint8_t *)(bios + 0x5555) = 0xF0;
108
	myusec_delay(40);
109

110
	printf_debug("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, id1, id2);
111 112
	if (id1 == flash->manufacture_id && id2 == flash->model_id)
		return 1;
113

114
	return 0;
Ollie Lho's avatar
Ollie Lho committed
115
}
116

117
int erase_sector_jedec(volatile uint8_t *bios, unsigned int page)
Ollie Lho's avatar
Ollie Lho committed
118
{
119
	/*  Issue the Sector Erase command   */
120
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
121
	myusec_delay(10);
122
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
123
	myusec_delay(10);
124
	*(volatile uint8_t *)(bios + 0x5555) = 0x80;
Ollie Lho's avatar
Ollie Lho committed
125
	myusec_delay(10);
126

127
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
Ollie Lho's avatar
Ollie Lho committed
128
	myusec_delay(10);
129
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
Ollie Lho's avatar
Ollie Lho committed
130
	myusec_delay(10);
131
	*(volatile uint8_t *)(bios + page) = 0x30;
Ollie Lho's avatar
Ollie Lho committed
132
	myusec_delay(10);
133 134 135 136

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

Uwe Hermann's avatar
Uwe Hermann committed
137
	return 0;
138
}
139

140
int erase_block_jedec(volatile uint8_t *bios, unsigned int block)
141 142
{
	/*  Issue the Sector Erase command   */
143
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
144
	myusec_delay(10);
145
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
146
	myusec_delay(10);
147
	*(volatile uint8_t *)(bios + 0x5555) = 0x80;
148
	myusec_delay(10);
149

150
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
151
	myusec_delay(10);
152
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
153
	myusec_delay(10);
154
	*(volatile uint8_t *)(bios + block) = 0x50;
155
	myusec_delay(10);
156

Ollie Lho's avatar
Ollie Lho committed
157 158
	/* wait for Toggle bit ready         */
	toggle_ready_jedec(bios);
159

Uwe Hermann's avatar
Uwe Hermann committed
160
	return 0;
161 162
}

163
int erase_chip_jedec(struct flashchip *flash)
164
{
165
	volatile uint8_t *bios = flash->virtual_memory;
166

167
	/*  Issue the JEDEC Chip Erase command   */
168
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
Ollie Lho's avatar
Ollie Lho committed
169
	myusec_delay(10);
170
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
171
	myusec_delay(10);
172
	*(volatile uint8_t *)(bios + 0x5555) = 0x80;
Ollie Lho's avatar
Ollie Lho committed
173
	myusec_delay(10);
174

175
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
Ollie Lho's avatar
Ollie Lho committed
176
	myusec_delay(10);
177
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
Ollie Lho's avatar
Ollie Lho committed
178
	myusec_delay(10);
179
	*(volatile uint8_t *)(bios + 0x5555) = 0x10;
Ollie Lho's avatar
Ollie Lho committed
180 181
	myusec_delay(10);

182
	toggle_ready_jedec(bios);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
183

Uwe Hermann's avatar
Uwe Hermann committed
184
	return 0;
185 186
}

187 188
int write_page_write_jedec(volatile uint8_t *bios, uint8_t *src,
			   volatile uint8_t *dst, int page_size)
189
{
190 191 192
	int i, tried = 0, start_index = 0, ok;
	volatile uint8_t *d = dst;
	uint8_t *s = src;
193

194
retry:
195
	/* Issue JEDEC Data Unprotect comand */
196 197 198
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
	*(volatile uint8_t *)(bios + 0x5555) = 0xA0;
199

200
	/* transfer data from source to destination */
201
	for (i = start_index; i < page_size; i++) {
202
		/* If the data is 0xFF, don't program it */
203
		if (*src != 0xFF)
204 205 206
			*dst = *src;
		dst++;
		src++;
207 208 209
	}

	toggle_ready_jedec(dst - 1);
210

211 212 213 214
	dst = d;
	src = s;
	ok = 1;
	for (i = 0; i < page_size; i++) {
215
		if (*dst != *src) {
216 217 218 219 220 221
			ok = 0;
			break;
		}
		dst++;
		src++;
	}
222

223 224
	if (!ok && tried++ < MAX_REFLASH_TRIES) {
		start_index = i;
225 226
		goto retry;
	}
227
	if (!ok) {
228 229
		fprintf(stderr, " page %d failed!\n",
			(unsigned int)(d - bios) / page_size);
230
	}
Uwe Hermann's avatar
Uwe Hermann committed
231
	return !ok;
232 233
}

234 235
int write_byte_program_jedec(volatile uint8_t *bios, uint8_t *src,
			     volatile uint8_t *dst)
Ollie Lho's avatar
Ollie Lho committed
236
{
237
	int tried = 0, ok = 1;
238

239
	/* If the data is 0xFF, don't program it */
Ollie Lho's avatar
Ollie Lho committed
240
	if (*src == 0xFF) {
241
		return -1;
Ollie Lho's avatar
Ollie Lho committed
242
	}
243

244
retry:
Ollie Lho's avatar
Ollie Lho committed
245
	/* Issue JEDEC Byte Program command */
246 247 248
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
	*(volatile uint8_t *)(bios + 0x5555) = 0xA0;
249 250

	/* transfer data from source to destination */
Ollie Lho's avatar
Ollie Lho committed
251 252
	*dst = *src;
	toggle_ready_jedec(bios);
253

254
	if (*dst != *src && tried++ < MAX_REFLASH_TRIES) {
255 256
		goto retry;
	}
257

258
	if (tried >= MAX_REFLASH_TRIES)
259
		ok = 0;
260

Uwe Hermann's avatar
Uwe Hermann committed
261
	return !ok;
Ollie Lho's avatar
Ollie Lho committed
262 263
}

264 265
int write_sector_jedec(volatile uint8_t *bios, uint8_t *src,
		       volatile uint8_t *dst, unsigned int page_size)
266 267 268 269
{
	int i;

	for (i = 0; i < page_size; i++) {
270 271
		write_byte_program_jedec(bios, src, dst);
		dst++, src++;
272 273
	}

Uwe Hermann's avatar
Uwe Hermann committed
274
	return 0;
275 276
}

277
int write_jedec(struct flashchip *flash, uint8_t *buf)
278 279
{
	int i;
Ollie Lho's avatar
Ollie Lho committed
280 281
	int total_size = flash->total_size * 1024;
	int page_size = flash->page_size;
282
	volatile uint8_t *bios = flash->virtual_memory;
283

284
	erase_chip_jedec(flash);
285 286 287
	// dumb check if erase was successful.
	for (i = 0; i < total_size; i++) {
		if (bios[i] != (uint8_t) 0xff) {
288
			printf("ERASE FAILED @%d, val %02x!\n", i, bios[i]);
289 290 291
			return -1;
		}
	}
292

293
	printf("Programming page: ");
294 295
	for (i = 0; i < total_size / page_size; i++) {
		printf("%04d at address: 0x%08x", i, i * page_size);
296 297
		write_page_write_jedec(bios, buf + i * page_size,
				       bios + i * page_size, page_size);
Ollie Lho's avatar
Ollie Lho committed
298
		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");
299 300
	}
	printf("\n");
301
	protect_jedec(bios);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
302

Uwe Hermann's avatar
Uwe Hermann committed
303
	return 0;
304
}