Blame view

board/lubbock/flash.c 8.9 KB
ea8015b85   wdenk   Initial revision
1
  /*
db2f721ff   wdenk   * Patch by Rune T...
2
   * (C) Copyright 2001
ea8015b85   wdenk   Initial revision
3
4
   * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
   *
db2f721ff   wdenk   * Patch by Rune T...
5
6
   * (C) Copyright 2001
   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
ea8015b85   wdenk   Initial revision
7
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
8
   * SPDX-License-Identifier:	GPL-2.0+
ea8015b85   wdenk   Initial revision
9
10
11
   */
  
  #include <common.h>
db2f721ff   wdenk   * Patch by Rune T...
12
  #include <linux/byteorder/swab.h>
ea8015b85   wdenk   Initial revision
13

ea8015b85   wdenk   Initial revision
14

6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
15
  flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];	/* info for FLASH chips    */
ea8015b85   wdenk   Initial revision
16

db2f721ff   wdenk   * Patch by Rune T...
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  /* Board support for 1 or 2 flash devices */
  #define FLASH_PORT_WIDTH32
  #undef FLASH_PORT_WIDTH16
  
  #ifdef FLASH_PORT_WIDTH16
  #define FLASH_PORT_WIDTH		ushort
  #define FLASH_PORT_WIDTHV		vu_short
  #define SWAP(x)               __swab16(x)
  #else
  #define FLASH_PORT_WIDTH		ulong
  #define FLASH_PORT_WIDTHV		vu_long
  #define SWAP(x)               __swab32(x)
  #endif
  
  #define FPW	   FLASH_PORT_WIDTH
  #define FPWV   FLASH_PORT_WIDTHV
  
  #define mb() __asm__ __volatile__ ("" : : : "memory")
ea8015b85   wdenk   Initial revision
35
36
  
  /*-----------------------------------------------------------------------
db2f721ff   wdenk   * Patch by Rune T...
37
   * Functions
ea8015b85   wdenk   Initial revision
38
   */
db2f721ff   wdenk   * Patch by Rune T...
39
  static ulong flash_get_size (FPW *addr, flash_info_t *info);
06d01dbe0   wdenk   * Avoid flicker o...
40
41
42
  static int write_data (flash_info_t *info, ulong dest, FPW data);
  static void flash_get_offsets (ulong base, flash_info_t *info);
  void inline spin_wheel (void);
ea8015b85   wdenk   Initial revision
43

db2f721ff   wdenk   * Patch by Rune T...
44
45
46
47
  /*-----------------------------------------------------------------------
   */
  
  unsigned long flash_init (void)
ea8015b85   wdenk   Initial revision
48
  {
06d01dbe0   wdenk   * Avoid flicker o...
49
50
  	int i;
  	ulong size = 0;
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
51
  	for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
06d01dbe0   wdenk   * Avoid flicker o...
52
53
54
55
56
57
58
59
60
61
  		switch (i) {
  		case 0:
  			flash_get_size ((FPW *) PHYS_FLASH_1, &flash_info[i]);
  			flash_get_offsets (PHYS_FLASH_1, &flash_info[i]);
  			break;
  		case 1:
  			flash_get_size ((FPW *) PHYS_FLASH_2, &flash_info[i]);
  			flash_get_offsets (PHYS_FLASH_2, &flash_info[i]);
  			break;
  		default:
5f535fe17   wdenk   * Patches by Ande...
62
63
  			panic ("configured too many flash banks!
  ");
06d01dbe0   wdenk   * Avoid flicker o...
64
65
66
67
68
69
70
71
  			break;
  		}
  		size += flash_info[i].size;
  	}
  
  	/* Protect monitor and environment sectors
  	 */
  	flash_protect ( FLAG_PROTECT_SET,
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
72
73
  			CONFIG_SYS_FLASH_BASE,
  			CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1,
06d01dbe0   wdenk   * Avoid flicker o...
74
75
76
  			&flash_info[0] );
  
  	flash_protect ( FLAG_PROTECT_SET,
0e8d15866   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ENV ma...
77
78
  			CONFIG_ENV_ADDR,
  			CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0] );
06d01dbe0   wdenk   * Avoid flicker o...
79
80
  
  	return size;
ea8015b85   wdenk   Initial revision
81
82
83
84
  }
  
  /*-----------------------------------------------------------------------
   */
db2f721ff   wdenk   * Patch by Rune T...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  static void flash_get_offsets (ulong base, flash_info_t *info)
  {
  	int i;
  
  	if (info->flash_id == FLASH_UNKNOWN) {
  		return;
  	}
  
  	if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
  		for (i = 0; i < info->sector_count; i++) {
  			info->start[i] = base + (i * PHYS_FLASH_SECT_SIZE);
  			info->protect[i] = 0;
  		}
  	}
  }
  
  /*-----------------------------------------------------------------------
   */
06d01dbe0   wdenk   * Avoid flicker o...
103
  void flash_print_info (flash_info_t *info)
ea8015b85   wdenk   Initial revision
104
  {
db2f721ff   wdenk   * Patch by Rune T...
105
  	int i;
ea8015b85   wdenk   Initial revision
106

db2f721ff   wdenk   * Patch by Rune T...
107
108
109
110
  	if (info->flash_id == FLASH_UNKNOWN) {
  		printf ("missing or unknown FLASH type
  ");
  		return;
06d01dbe0   wdenk   * Avoid flicker o...
111
  	}
ea8015b85   wdenk   Initial revision
112

db2f721ff   wdenk   * Patch by Rune T...
113
  	switch (info->flash_id & FLASH_VENDMASK) {
06d01dbe0   wdenk   * Avoid flicker o...
114
115
116
117
118
119
  	case FLASH_MAN_INTEL:
  		printf ("INTEL ");
  		break;
  	default:
  		printf ("Unknown Vendor ");
  		break;
db2f721ff   wdenk   * Patch by Rune T...
120
121
122
  	}
  
  	switch (info->flash_id & FLASH_TYPEMASK) {
06d01dbe0   wdenk   * Avoid flicker o...
123
124
125
126
127
128
129
130
131
  	case FLASH_28F128J3A:
  		printf ("28F128J3A
  ");
  		break;
  	default:
  		printf ("Unknown Chip Type
  ");
  		break;
  	}
ea8015b85   wdenk   Initial revision
132

db2f721ff   wdenk   * Patch by Rune T...
133
134
  	printf ("  Size: %ld MB in %d Sectors
  ",
06d01dbe0   wdenk   * Avoid flicker o...
135
  			info->size >> 20, info->sector_count);
ea8015b85   wdenk   Initial revision
136

db2f721ff   wdenk   * Patch by Rune T...
137
  	printf ("  Sector Start Addresses:");
06d01dbe0   wdenk   * Avoid flicker o...
138
139
140
141
  	for (i = 0; i < info->sector_count; ++i) {
  		if ((i % 5) == 0)
  			printf ("
     ");
db2f721ff   wdenk   * Patch by Rune T...
142
143
  		printf (" %08lX%s",
  			info->start[i],
06d01dbe0   wdenk   * Avoid flicker o...
144
145
146
147
  			info->protect[i] ? " (RO)" : "     ");
  	}
  	printf ("
  ");
db2f721ff   wdenk   * Patch by Rune T...
148
149
150
151
152
153
154
155
156
157
158
  	return;
  }
  
  /*
   * The following code cannot be run from FLASH!
   */
  static ulong flash_get_size (FPW *addr, flash_info_t *info)
  {
  	volatile FPW value;
  
  	/* Write auto select command: read Manufacturer ID */
06d01dbe0   wdenk   * Avoid flicker o...
159
160
161
  	addr[0x5555] = (FPW) 0x00AA00AA;
  	addr[0x2AAA] = (FPW) 0x00550055;
  	addr[0x5555] = (FPW) 0x00900090;
db2f721ff   wdenk   * Patch by Rune T...
162

06d01dbe0   wdenk   * Avoid flicker o...
163
  	mb ();
db2f721ff   wdenk   * Patch by Rune T...
164
  	value = addr[0];
06d01dbe0   wdenk   * Avoid flicker o...
165
  	switch (value) {
db2f721ff   wdenk   * Patch by Rune T...
166

06d01dbe0   wdenk   * Avoid flicker o...
167
168
169
  	case (FPW) INTEL_MANUFACT:
  		info->flash_id = FLASH_MAN_INTEL;
  		break;
db2f721ff   wdenk   * Patch by Rune T...
170
171
172
173
174
  
  	default:
  		info->flash_id = FLASH_UNKNOWN;
  		info->sector_count = 0;
  		info->size = 0;
06d01dbe0   wdenk   * Avoid flicker o...
175
176
  		addr[0] = (FPW) 0x00FF00FF;	/* restore read mode */
  		return (0);			/* no or unknown flash  */
db2f721ff   wdenk   * Patch by Rune T...
177
  	}
06d01dbe0   wdenk   * Avoid flicker o...
178
179
  	mb ();
  	value = addr[1];			/* device ID        */
db2f721ff   wdenk   * Patch by Rune T...
180

06d01dbe0   wdenk   * Avoid flicker o...
181
  	switch (value) {
db2f721ff   wdenk   * Patch by Rune T...
182

06d01dbe0   wdenk   * Avoid flicker o...
183
184
185
186
187
  	case (FPW) INTEL_ID_28F128J3A:
  		info->flash_id += FLASH_28F128J3A;
  		info->sector_count = 128;
  		info->size = 0x02000000;
  		break;				/* => 16 MB     */
db2f721ff   wdenk   * Patch by Rune T...
188
189
190
191
192
  
  	default:
  		info->flash_id = FLASH_UNKNOWN;
  		break;
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
193
  	if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) {
db2f721ff   wdenk   * Patch by Rune T...
194
195
  		printf ("** ERROR: sector count %d > max (%d) **
  ",
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
196
197
  			info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
  		info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
06d01dbe0   wdenk   * Avoid flicker o...
198
  	}
ea8015b85   wdenk   Initial revision
199

06d01dbe0   wdenk   * Avoid flicker o...
200
  	addr[0] = (FPW) 0x00FF00FF;		/* restore read mode */
db2f721ff   wdenk   * Patch by Rune T...
201
202
  
  	return (info->size);
ea8015b85   wdenk   Initial revision
203
  }
db2f721ff   wdenk   * Patch by Rune T...
204

ea8015b85   wdenk   Initial revision
205
206
  /*-----------------------------------------------------------------------
   */
06d01dbe0   wdenk   * Avoid flicker o...
207
  int flash_erase (flash_info_t *info, int s_first, int s_last)
ea8015b85   wdenk   Initial revision
208
  {
90729c023   Anatolij Gustschin   board/lubbock/fla...
209
  	int prot, sect;
a60d1e5b8   Graeme Russ   Timer: Fix misuse...
210
  	ulong type, start;
db2f721ff   wdenk   * Patch by Rune T...
211
  	int rcode = 0;
ea8015b85   wdenk   Initial revision
212

06d01dbe0   wdenk   * Avoid flicker o...
213
  	if ((s_first < 0) || (s_first > s_last)) {
db2f721ff   wdenk   * Patch by Rune T...
214
215
216
217
218
219
220
221
  		if (info->flash_id == FLASH_UNKNOWN) {
  			printf ("- missing
  ");
  		} else {
  			printf ("- no sectors to erase
  ");
  		}
  		return 1;
06d01dbe0   wdenk   * Avoid flicker o...
222
  	}
ea8015b85   wdenk   Initial revision
223

db2f721ff   wdenk   * Patch by Rune T...
224
225
226
227
228
229
  	type = (info->flash_id & FLASH_VENDMASK);
  	if ((type != FLASH_MAN_INTEL)) {
  		printf ("Can't erase unknown flash type %08lx - aborted
  ",
  			info->flash_id);
  		return 1;
06d01dbe0   wdenk   * Avoid flicker o...
230
  	}
ea8015b85   wdenk   Initial revision
231

06d01dbe0   wdenk   * Avoid flicker o...
232
233
234
235
236
  	prot = 0;
  	for (sect = s_first; sect <= s_last; ++sect) {
  		if (info->protect[sect]) {
  			prot++;
  		}
ea8015b85   wdenk   Initial revision
237
  	}
ea8015b85   wdenk   Initial revision
238

db2f721ff   wdenk   * Patch by Rune T...
239
240
241
242
243
244
245
246
  	if (prot) {
  		printf ("- Warning: %d protected sectors will not be erased!
  ",
  			prot);
  	} else {
  		printf ("
  ");
  	}
06d01dbe0   wdenk   * Avoid flicker o...
247
  	/* Disable interrupts which might cause a timeout here */
90729c023   Anatolij Gustschin   board/lubbock/fla...
248
  	disable_interrupts();
ea8015b85   wdenk   Initial revision
249

06d01dbe0   wdenk   * Avoid flicker o...
250
251
  	/* Start erase on unprotected sectors */
  	for (sect = s_first; sect <= s_last; sect++) {
db2f721ff   wdenk   * Patch by Rune T...
252
  		if (info->protect[sect] == 0) {	/* not protected */
06d01dbe0   wdenk   * Avoid flicker o...
253
  			FPWV *addr = (FPWV *) (info->start[sect]);
db2f721ff   wdenk   * Patch by Rune T...
254
  			FPW status;
ea8015b85   wdenk   Initial revision
255

06d01dbe0   wdenk   * Avoid flicker o...
256
  			printf ("Erasing sector %2d ... ", sect);
ea8015b85   wdenk   Initial revision
257

06d01dbe0   wdenk   * Avoid flicker o...
258
  			/* arm simple, non interrupt dependent timer */
a60d1e5b8   Graeme Russ   Timer: Fix misuse...
259
  			start = get_timer(0);
ea8015b85   wdenk   Initial revision
260

06d01dbe0   wdenk   * Avoid flicker o...
261
262
263
  			*addr = (FPW) 0x00500050;	/* clear status register */
  			*addr = (FPW) 0x00200020;	/* erase setup */
  			*addr = (FPW) 0x00D000D0;	/* erase confirm */
ea8015b85   wdenk   Initial revision
264

06d01dbe0   wdenk   * Avoid flicker o...
265
  			while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) {
a60d1e5b8   Graeme Russ   Timer: Fix misuse...
266
  				if (get_timer(start) > CONFIG_SYS_FLASH_ERASE_TOUT) {
db2f721ff   wdenk   * Patch by Rune T...
267
268
  					printf ("Timeout
  ");
06d01dbe0   wdenk   * Avoid flicker o...
269
270
  					*addr = (FPW) 0x00B000B0;	/* suspend erase     */
  					*addr = (FPW) 0x00FF00FF;	/* reset to read mode */
db2f721ff   wdenk   * Patch by Rune T...
271
272
  					rcode = 1;
  					break;
06d01dbe0   wdenk   * Avoid flicker o...
273
274
  				}
  			}
ea8015b85   wdenk   Initial revision
275

06d01dbe0   wdenk   * Avoid flicker o...
276
277
  			*addr = 0x00500050;	/* clear status register cmd.   */
  			*addr = 0x00FF00FF;	/* resest to read mode          */
ea8015b85   wdenk   Initial revision
278

db2f721ff   wdenk   * Patch by Rune T...
279
280
  			printf (" done
  ");
06d01dbe0   wdenk   * Avoid flicker o...
281
282
  		}
  	}
db2f721ff   wdenk   * Patch by Rune T...
283
  	return rcode;
ea8015b85   wdenk   Initial revision
284
285
286
  }
  
  /*-----------------------------------------------------------------------
db2f721ff   wdenk   * Patch by Rune T...
287
288
289
290
291
   * Copy memory to flash, returns:
   * 0 - OK
   * 1 - write timeout
   * 2 - Flash not erased
   * 4 - Flash not identified
ea8015b85   wdenk   Initial revision
292
293
294
295
   */
  
  int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
  {
06d01dbe0   wdenk   * Avoid flicker o...
296
  	ulong cp, wp;
db2f721ff   wdenk   * Patch by Rune T...
297
298
  	FPW data;
  	int count, i, l, rc, port_width;
ea8015b85   wdenk   Initial revision
299

db2f721ff   wdenk   * Patch by Rune T...
300
301
302
303
304
305
306
307
308
309
310
  	if (info->flash_id == FLASH_UNKNOWN) {
  		return 4;
  	}
  /* get lower word aligned address */
  #ifdef FLASH_PORT_WIDTH16
  	wp = (addr & ~1);
  	port_width = 2;
  #else
  	wp = (addr & ~3);
  	port_width = 4;
  #endif
ea8015b85   wdenk   Initial revision
311

06d01dbe0   wdenk   * Avoid flicker o...
312
313
314
315
316
317
318
319
320
  	/*
  	 * handle unaligned start bytes
  	 */
  	if ((l = addr - wp) != 0) {
  		data = 0;
  		for (i = 0, cp = wp; i < l; ++i, ++cp) {
  			data = (data << 8) | (*(uchar *) cp);
  		}
  		for (; i < port_width && cnt > 0; ++i) {
db2f721ff   wdenk   * Patch by Rune T...
321
  			data = (data << 8) | *src++;
06d01dbe0   wdenk   * Avoid flicker o...
322
323
324
325
326
327
  			--cnt;
  			++cp;
  		}
  		for (; cnt == 0 && i < port_width; ++i, ++cp) {
  			data = (data << 8) | (*(uchar *) cp);
  		}
ea8015b85   wdenk   Initial revision
328

06d01dbe0   wdenk   * Avoid flicker o...
329
330
331
  		if ((rc = write_data (info, wp, SWAP (data))) != 0) {
  			return (rc);
  		}
db2f721ff   wdenk   * Patch by Rune T...
332
  		wp += port_width;
06d01dbe0   wdenk   * Avoid flicker o...
333
  	}
ea8015b85   wdenk   Initial revision
334

06d01dbe0   wdenk   * Avoid flicker o...
335
336
337
  	/*
  	 * handle word aligned part
  	 */
db2f721ff   wdenk   * Patch by Rune T...
338
339
340
  	count = 0;
  	while (cnt >= port_width) {
  		data = 0;
06d01dbe0   wdenk   * Avoid flicker o...
341
  		for (i = 0; i < port_width; ++i) {
db2f721ff   wdenk   * Patch by Rune T...
342
343
  			data = (data << 8) | *src++;
  		}
06d01dbe0   wdenk   * Avoid flicker o...
344
345
346
347
  		if ((rc = write_data (info, wp, SWAP (data))) != 0) {
  			return (rc);
  		}
  		wp += port_width;
db2f721ff   wdenk   * Patch by Rune T...
348
  		cnt -= port_width;
06d01dbe0   wdenk   * Avoid flicker o...
349
350
  		if (count++ > 0x800) {
  			spin_wheel ();
db2f721ff   wdenk   * Patch by Rune T...
351
352
  			count = 0;
  		}
06d01dbe0   wdenk   * Avoid flicker o...
353
  	}
ea8015b85   wdenk   Initial revision
354

06d01dbe0   wdenk   * Avoid flicker o...
355
  	if (cnt == 0) {
db2f721ff   wdenk   * Patch by Rune T...
356
  		return (0);
06d01dbe0   wdenk   * Avoid flicker o...
357
  	}
ea8015b85   wdenk   Initial revision
358

06d01dbe0   wdenk   * Avoid flicker o...
359
360
361
362
363
  	/*
  	 * handle unaligned tail bytes
  	 */
  	data = 0;
  	for (i = 0, cp = wp; i < port_width && cnt > 0; ++i, ++cp) {
db2f721ff   wdenk   * Patch by Rune T...
364
  		data = (data << 8) | *src++;
06d01dbe0   wdenk   * Avoid flicker o...
365
366
367
368
  		--cnt;
  	}
  	for (; i < port_width; ++i, ++cp) {
  		data = (data << 8) | (*(uchar *) cp);
db2f721ff   wdenk   * Patch by Rune T...
369
  	}
06d01dbe0   wdenk   * Avoid flicker o...
370
  	return (write_data (info, wp, SWAP (data)));
db2f721ff   wdenk   * Patch by Rune T...
371
372
373
374
375
376
377
378
379
380
  }
  
  /*-----------------------------------------------------------------------
   * Write a word or halfword to Flash, returns:
   * 0 - OK
   * 1 - write timeout
   * 2 - Flash not erased
   */
  static int write_data (flash_info_t *info, ulong dest, FPW data)
  {
06d01dbe0   wdenk   * Avoid flicker o...
381
  	FPWV *addr = (FPWV *) dest;
db2f721ff   wdenk   * Patch by Rune T...
382
  	ulong status;
a60d1e5b8   Graeme Russ   Timer: Fix misuse...
383
  	ulong start;
db2f721ff   wdenk   * Patch by Rune T...
384
385
386
  
  	/* Check if Flash is (sufficiently) erased */
  	if ((*addr & data) != data) {
06d01dbe0   wdenk   * Avoid flicker o...
387
388
  		printf ("not erased at %08lx (%lx)
  ", (ulong) addr, *addr);
db2f721ff   wdenk   * Patch by Rune T...
389
390
391
  		return (2);
  	}
  	/* Disable interrupts which might cause a timeout here */
90729c023   Anatolij Gustschin   board/lubbock/fla...
392
  	disable_interrupts();
db2f721ff   wdenk   * Patch by Rune T...
393

06d01dbe0   wdenk   * Avoid flicker o...
394
  	*addr = (FPW) 0x00400040;	/* write setup */
db2f721ff   wdenk   * Patch by Rune T...
395
396
397
  	*addr = data;
  
  	/* arm simple, non interrupt dependent timer */
a60d1e5b8   Graeme Russ   Timer: Fix misuse...
398
  	start = get_timer(0);
db2f721ff   wdenk   * Patch by Rune T...
399
400
  
  	/* wait while polling the status register */
06d01dbe0   wdenk   * Avoid flicker o...
401
  	while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) {
c4f4c760c   Marek Vasut   PXA: Fix Lubbock,...
402
  		if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
06d01dbe0   wdenk   * Avoid flicker o...
403
  			*addr = (FPW) 0x00FF00FF;	/* restore read mode */
db2f721ff   wdenk   * Patch by Rune T...
404
405
  			return (1);
  		}
06d01dbe0   wdenk   * Avoid flicker o...
406
  	}
ea8015b85   wdenk   Initial revision
407

06d01dbe0   wdenk   * Avoid flicker o...
408
  	*addr = (FPW) 0x00FF00FF;	/* restore read mode */
db2f721ff   wdenk   * Patch by Rune T...
409
410
411
  
  	return (0);
  }
06d01dbe0   wdenk   * Avoid flicker o...
412
  void inline spin_wheel (void)
db2f721ff   wdenk   * Patch by Rune T...
413
  {
06d01dbe0   wdenk   * Avoid flicker o...
414
415
  	static int p = 0;
  	static char w[] = "\\/-";
db2f721ff   wdenk   * Patch by Rune T...
416

06d01dbe0   wdenk   * Avoid flicker o...
417
418
  	printf ("\010%c", w[p]);
  	(++p == 3) ? (p = 0) : 0;
ea8015b85   wdenk   Initial revision
419
  }