jedec.c 6.95 KB
Newer Older
1
/*
2
 * This file is part of the flashrom project.
3 4
 *
 * Copyright 2000 Silicon Integrated System Corporation
5 6
 * Copyright 2006 Giampiero Giancipoli <gianci@email.it>
 * Copyright 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
	myusec_delay(10);

	/* Read product ID */
95 96
	id1 = *(volatile uint8_t *)bios;
	id2 = *(volatile uint8_t *)(bios + 0x01);
97 98

	/* Issue JEDEC Product ID Exit command */
99
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
100
	myusec_delay(10);
101
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
102
	myusec_delay(10);
103
	*(volatile uint8_t *)(bios + 0x5555) = 0xF0;
104
	myusec_delay(10);
105

106
	printf_debug("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, id1, id2);
107 108
	if (id1 == flash->manufacture_id && id2 == flash->model_id)
		return 1;
109

110
	return 0;
Ollie Lho's avatar
Ollie Lho committed
111
}
112

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

123
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
Ollie Lho's avatar
Ollie Lho committed
124
	myusec_delay(10);
125
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
Ollie Lho's avatar
Ollie Lho committed
126
	myusec_delay(10);
127
	*(volatile uint8_t *)(bios + page) = 0x30;
Ollie Lho's avatar
Ollie Lho committed
128
	myusec_delay(10);
129 130 131 132

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

Uwe Hermann's avatar
Uwe Hermann committed
133
	return 0;
134
}
135

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

146
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
147
	myusec_delay(10);
148
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
149
	myusec_delay(10);
150
	*(volatile uint8_t *)(bios + block) = 0x50;
151
	myusec_delay(10);
152

Ollie Lho's avatar
Ollie Lho committed
153 154
	/* wait for Toggle bit ready         */
	toggle_ready_jedec(bios);
155

Uwe Hermann's avatar
Uwe Hermann committed
156
	return 0;
157 158
}

159
int erase_chip_jedec(struct flashchip *flash)
160
{
161
	volatile uint8_t *bios = flash->virtual_memory;
162

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

171
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
Ollie Lho's avatar
Ollie Lho committed
172
	myusec_delay(10);
173
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
Ollie Lho's avatar
Ollie Lho committed
174
	myusec_delay(10);
175
	*(volatile uint8_t *)(bios + 0x5555) = 0x10;
Ollie Lho's avatar
Ollie Lho committed
176 177
	myusec_delay(10);

178
	toggle_ready_jedec(bios);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
179

Uwe Hermann's avatar
Uwe Hermann committed
180
	return 0;
181 182
}

183 184
int write_page_write_jedec(volatile uint8_t *bios, uint8_t *src,
			   volatile uint8_t *dst, int page_size)
185
{
186 187 188
	int i, tried = 0, start_index = 0, ok;
	volatile uint8_t *d = dst;
	uint8_t *s = src;
189

190
retry:
191
	/* Issue JEDEC Data Unprotect comand */
192 193 194
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
	*(volatile uint8_t *)(bios + 0x5555) = 0xA0;
195

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

	toggle_ready_jedec(dst - 1);
206

207 208 209 210
	dst = d;
	src = s;
	ok = 1;
	for (i = 0; i < page_size; i++) {
211
		if (*dst != *src) {
212 213 214 215 216 217
			ok = 0;
			break;
		}
		dst++;
		src++;
	}
218

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

230 231
int write_byte_program_jedec(volatile uint8_t *bios, uint8_t *src,
			     volatile uint8_t *dst)
Ollie Lho's avatar
Ollie Lho committed
232
{
233
	int tried = 0, ok = 1;
234

235
	/* If the data is 0xFF, don't program it */
Ollie Lho's avatar
Ollie Lho committed
236
	if (*src == 0xFF) {
237
		return -1;
Ollie Lho's avatar
Ollie Lho committed
238
	}
239

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

	/* transfer data from source to destination */
Ollie Lho's avatar
Ollie Lho committed
247 248
	*dst = *src;
	toggle_ready_jedec(bios);
249

250
	if (*dst != *src && tried++ < MAX_REFLASH_TRIES) {
251 252
		goto retry;
	}
253

254
	if (tried >= MAX_REFLASH_TRIES)
255
		ok = 0;
256

Uwe Hermann's avatar
Uwe Hermann committed
257
	return !ok;
Ollie Lho's avatar
Ollie Lho committed
258 259
}

260 261
int write_sector_jedec(volatile uint8_t *bios, uint8_t *src,
		       volatile uint8_t *dst, unsigned int page_size)
262 263 264 265
{
	int i;

	for (i = 0; i < page_size; i++) {
266 267
		write_byte_program_jedec(bios, src, dst);
		dst++, src++;
268 269
	}

Uwe Hermann's avatar
Uwe Hermann committed
270
	return 0;
271 272
}

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

280
	erase_chip_jedec(flash);
281 282 283 284 285 286 287
	// dumb check if erase was successful.
	for (i = 0; i < total_size; i++) {
		if (bios[i] != (uint8_t) 0xff) {
			printf("ERASE FAILED\n");
			return -1;
		}
	}
288

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

Uwe Hermann's avatar
Uwe Hermann committed
299
	return 0;
300
}