jedec.c 6.99 KB
Newer Older
1 2 3 4 5
/*
 * jedec.c: driver for programming JEDEC standard flash parts
 *
 *
 * Copyright 2000 Silicon Integrated System Corporation
6 7
 * Copyright 2006 Giampiero Giancipoli <gianci@email.it>
 * Copyright 2006 coresystems GmbH <info@coresystems.de>
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 *	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.
 *
 *	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.
 *
 *	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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *
 * Reference:
 *
 */

Ronald G. Minnich's avatar
Ronald G. Minnich committed
28
#include <stdio.h>
29
#include <stdint.h>
30 31
#include "flash.h"

32 33
#define MAX_REFLASH_TRIES 0x10

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 82 83 84 85
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);
}

86
int probe_jedec(struct flashchip *flash)
87
{
88
	volatile uint8_t *bios = flash->virtual_memory;
89
	uint8_t id1, id2;
90 91

	/* Issue JEDEC Product ID Entry command */
92
	*(volatile uint8_t *)(bios + 0x5555) = 0xAA;
93
	myusec_delay(10);
94
	*(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
95
	myusec_delay(10);
96
	*(volatile uint8_t *)(bios + 0x5555) = 0x90;
97 98 99
	myusec_delay(10);

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

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

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

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

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

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

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

	return (0);
}
140

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

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

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

161
	return (0);
162 163
}

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

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

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

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

185 186 187
	return (0);
}

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

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

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

	toggle_ready_jedec(dst - 1);
211

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

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

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

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

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

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

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

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

	return (!ok);
Ollie Lho's avatar
Ollie Lho committed
263 264
}

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

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

	return (0);
276 277
}

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

285
	erase_chip_jedec(flash);
286 287 288 289 290 291 292
	// 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;
		}
	}
293

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

304
	return (0);
305
}