blob: 87368564afa2e14dd1289674a51fcda231752374 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
TsiChung Liewdd8513c2008-07-23 17:11:47 -05002/*
3 * (C) Copyright 2000-2003
4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 *
6 * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
7 * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
TsiChung Liewdd8513c2008-07-23 17:11:47 -05008 */
9
10#include <common.h>
Simon Glass8e201882020-05-10 11:39:54 -060011#include <flash.h>
Simon Glass8f3f7612019-11-14 12:57:42 -070012#include <irq_func.h>
TsiChung Liewdd8513c2008-07-23 17:11:47 -050013
14#include <asm/immap.h>
15
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020016#ifndef CONFIG_SYS_FLASH_CFI
TsiChung Liewdd8513c2008-07-23 17:11:47 -050017typedef unsigned short FLASH_PORT_WIDTH;
18typedef volatile unsigned short FLASH_PORT_WIDTHV;
19
20#define FPW FLASH_PORT_WIDTH
21#define FPWV FLASH_PORT_WIDTHV
22
23#define FLASH_CYCLE1 0x5555
24#define FLASH_CYCLE2 0x2aaa
25
26#define SYNC __asm__("nop")
27
28/*-----------------------------------------------------------------------
29 * Functions
30 */
31
32ulong flash_get_size(FPWV * addr, flash_info_t * info);
33int flash_get_offsets(ulong base, flash_info_t * info);
34int write_word(flash_info_t * info, FPWV * dest, u16 data);
Tom Rini03183832017-05-08 22:14:35 -040035static inline void spin_wheel(void);
TsiChung Liewdd8513c2008-07-23 17:11:47 -050036
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020037flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
TsiChung Liewdd8513c2008-07-23 17:11:47 -050038
39ulong flash_init(void)
40{
41 ulong size = 0;
42 ulong fbase = 0;
43
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020044 fbase = (ulong) CONFIG_SYS_FLASH_BASE;
TsiChung Liewdd8513c2008-07-23 17:11:47 -050045 flash_get_size((FPWV *) fbase, &flash_info[0]);
46 flash_get_offsets((ulong) fbase, &flash_info[0]);
47 fbase += flash_info[0].size;
48 size += flash_info[0].size;
49
50 /* Protect monitor and environment sectors */
51 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020052 CONFIG_SYS_MONITOR_BASE,
53 CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, &flash_info[0]);
TsiChung Liewdd8513c2008-07-23 17:11:47 -050054
55 return size;
56}
57
58int flash_get_offsets(ulong base, flash_info_t * info)
59{
Masahiro Yamadaf26bab32014-07-22 10:57:18 +090060 int i;
TsiChung Liewdd8513c2008-07-23 17:11:47 -050061
62 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
63
64 info->start[0] = base;
Masahiro Yamadaf26bab32014-07-22 10:57:18 +090065 info->protect[0] = 0;
66 for (i = 1; i < CONFIG_SYS_SST_SECT; i++) {
67 info->start[i] = info->start[i - 1]
68 + CONFIG_SYS_SST_SECTSZ;
69 info->protect[i] = 0;
TsiChung Liewdd8513c2008-07-23 17:11:47 -050070 }
71 }
72
73 return ERR_OK;
74}
75
76void flash_print_info(flash_info_t * info)
77{
78 int i;
79
80 switch (info->flash_id & FLASH_VENDMASK) {
81 case FLASH_MAN_SST:
82 printf("SST ");
83 break;
84 default:
85 printf("Unknown Vendor ");
86 break;
87 }
88
89 switch (info->flash_id & FLASH_TYPEMASK) {
90 case FLASH_SST6401B:
91 printf("SST39VF6401B\n");
92 break;
93 default:
94 printf("Unknown Chip Type\n");
95 return;
96 }
97
98 if (info->size > 0x100000) {
99 int remainder;
100
101 printf(" Size: %ld", info->size >> 20);
102
103 remainder = (info->size % 0x100000);
104 if (remainder) {
105 remainder >>= 10;
106 remainder = (int)((float)
107 (((float)remainder / (float)1024) *
108 10000));
109 printf(".%d ", remainder);
110 }
111
112 printf("MB in %d Sectors\n", info->sector_count);
113 } else
114 printf(" Size: %ld KB in %d Sectors\n",
115 info->size >> 10, info->sector_count);
116
117 printf(" Sector Start Addresses:");
118 for (i = 0; i < info->sector_count; ++i) {
119 if ((i % 5) == 0)
120 printf("\n ");
121 printf(" %08lX%s",
122 info->start[i], info->protect[i] ? " (RO)" : " ");
123 }
124 printf("\n");
125}
126
127/*
128 * The following code cannot be run from FLASH!
129 */
130ulong flash_get_size(FPWV * addr, flash_info_t * info)
131{
132 u16 value;
133
134 addr[FLASH_CYCLE1] = (FPWV) 0x00AA00AA; /* for Atmel, Intel ignores this */
135 addr[FLASH_CYCLE2] = (FPWV) 0x00550055; /* for Atmel, Intel ignores this */
136 addr[FLASH_CYCLE1] = (FPWV) 0x00900090; /* selects Intel or Atmel */
137
138 switch (addr[0] & 0xffff) {
139 case (u8) SST_MANUFACT:
140 info->flash_id = FLASH_MAN_SST;
141 value = addr[1];
142 break;
143 default:
144 printf("Unknown Flash\n");
145 info->flash_id = FLASH_UNKNOWN;
146 info->sector_count = 0;
147 info->size = 0;
148
149 *addr = (FPW) 0x00F000F0;
150 return (0); /* no or unknown flash */
151 }
152
153 switch (value) {
154 case (u16) SST_ID_xF6401B:
155 info->flash_id += FLASH_SST6401B;
156 break;
157 default:
158 info->flash_id = FLASH_UNKNOWN;
159 break;
160 }
161
162 info->sector_count = 0;
163 info->size = 0;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200164 info->sector_count = CONFIG_SYS_SST_SECT;
165 info->size = CONFIG_SYS_SST_SECT * CONFIG_SYS_SST_SECTSZ;
TsiChung Liewdd8513c2008-07-23 17:11:47 -0500166
167 /* reset ID mode */
168 *addr = (FPWV) 0x00F000F0;
169
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200170 if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) {
TsiChung Liewdd8513c2008-07-23 17:11:47 -0500171 printf("** ERROR: sector count %d > max (%d) **\n",
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200172 info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
173 info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
TsiChung Liewdd8513c2008-07-23 17:11:47 -0500174 }
175
176 return (info->size);
177}
178
179int flash_erase(flash_info_t * info, int s_first, int s_last)
180{
181 FPWV *addr;
182 int flag, prot, sect, count;
Masahiro Yamadac0d51fe2014-04-15 13:26:34 +0900183 ulong type, start;
TsiChung Liewdd8513c2008-07-23 17:11:47 -0500184 int rcode = 0, flashtype = 0;
185
186 if ((s_first < 0) || (s_first > s_last)) {
187 if (info->flash_id == FLASH_UNKNOWN)
188 printf("- missing\n");
189 else
190 printf("- no sectors to erase\n");
191 return 1;
192 }
193
194 type = (info->flash_id & FLASH_VENDMASK);
195
196 switch (type) {
197 case FLASH_MAN_SST:
198 flashtype = 1;
199 break;
200 default:
201 type = (info->flash_id & FLASH_VENDMASK);
202 printf("Can't erase unknown flash type %08lx - aborted\n",
203 info->flash_id);
204 return 1;
205 }
206
207 prot = 0;
208 for (sect = s_first; sect <= s_last; ++sect) {
209 if (info->protect[sect]) {
210 prot++;
211 }
212 }
213
214 if (prot)
215 printf("- Warning: %d protected sectors will not be erased!\n",
216 prot);
217 else
218 printf("\n");
219
220 flag = disable_interrupts();
221
222 start = get_timer(0);
TsiChung Liewdd8513c2008-07-23 17:11:47 -0500223
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200224 if ((s_last - s_first) == (CONFIG_SYS_SST_SECT - 1)) {
TsiChung Liewdd8513c2008-07-23 17:11:47 -0500225 if (prot == 0) {
226 addr = (FPWV *) info->start[0];
227
228 addr[FLASH_CYCLE1] = 0x00AA; /* unlock */
229 addr[FLASH_CYCLE2] = 0x0055; /* unlock */
230 addr[FLASH_CYCLE1] = 0x0080; /* erase mode */
231 addr[FLASH_CYCLE1] = 0x00AA; /* unlock */
232 addr[FLASH_CYCLE2] = 0x0055; /* unlock */
233 *addr = 0x0030; /* erase chip */
234
235 count = 0;
236 start = get_timer(0);
237
238 while ((*addr & 0x0080) != 0x0080) {
239 if (count++ > 0x10000) {
240 spin_wheel();
241 count = 0;
242 }
243
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200244 if (get_timer(start) > CONFIG_SYS_FLASH_ERASE_TOUT) {
TsiChung Liewdd8513c2008-07-23 17:11:47 -0500245 printf("Timeout\n");
246 *addr = 0x00F0; /* reset to read mode */
247
248 return 1;
249 }
250 }
251
252 *addr = 0x00F0; /* reset to read mode */
253
254 printf("\b. done\n");
255
256 if (flag)
257 enable_interrupts();
258
259 return 0;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200260 } else if (prot == CONFIG_SYS_SST_SECT) {
TsiChung Liewdd8513c2008-07-23 17:11:47 -0500261 return 1;
262 }
263 }
264
265 /* Start erase on unprotected sectors */
266 for (sect = s_first; sect <= s_last; sect++) {
267 if (info->protect[sect] == 0) { /* not protected */
268
269 addr = (FPWV *) (info->start[sect]);
270
271 printf(".");
272
273 /* arm simple, non interrupt dependent timer */
274 start = get_timer(0);
275
276 switch (flashtype) {
277 case 1:
278 {
279 FPWV *base; /* first address in bank */
280
281 flag = disable_interrupts();
282
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200283 base = (FPWV *) (CONFIG_SYS_FLASH_BASE); /* First sector */
TsiChung Liewdd8513c2008-07-23 17:11:47 -0500284
285 base[FLASH_CYCLE1] = 0x00AA; /* unlock */
286 base[FLASH_CYCLE2] = 0x0055; /* unlock */
287 base[FLASH_CYCLE1] = 0x0080; /* erase mode */
288 base[FLASH_CYCLE1] = 0x00AA; /* unlock */
289 base[FLASH_CYCLE2] = 0x0055; /* unlock */
290 *addr = 0x0050; /* erase sector */
291
292 if (flag)
293 enable_interrupts();
294
295 while ((*addr & 0x0080) != 0x0080) {
296 if (get_timer(start) >
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200297 CONFIG_SYS_FLASH_ERASE_TOUT) {
TsiChung Liewdd8513c2008-07-23 17:11:47 -0500298 printf("Timeout\n");
299 *addr = 0x00F0; /* reset to read mode */
300
301 rcode = 1;
302 break;
303 }
304 }
305
306 *addr = 0x00F0; /* reset to read mode */
307 break;
308 }
309 } /* switch (flashtype) */
310 }
311 }
312 printf(" done\n");
313
314 if (flag)
315 enable_interrupts();
316
317 return rcode;
318}
319
320int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
321{
322 ulong wp, count;
323 u16 data;
Masahiro Yamadac0d51fe2014-04-15 13:26:34 +0900324 int rc;
TsiChung Liewdd8513c2008-07-23 17:11:47 -0500325
326 if (info->flash_id == FLASH_UNKNOWN)
327 return 4;
328
329 /* get lower word aligned address */
330 wp = addr;
TsiChung Liewdd8513c2008-07-23 17:11:47 -0500331
332 /* handle unaligned start bytes */
333 if (wp & 1) {
334 data = *((FPWV *) wp);
335 data = (data << 8) | *src;
336
337 if ((rc = write_word(info, (FPWV *) wp, data)) != 0)
338 return (rc);
339
340 wp++;
341 cnt -= 1;
342 src++;
343 }
344
345 while (cnt >= 2) {
346 /*
347 * handle word aligned part
348 */
349 count = 0;
350 data = *((FPWV *) src);
351
352 if ((rc = write_word(info, (FPWV *) wp, data)) != 0)
353 return (rc);
354
355 wp += 2;
356 src += 2;
357 cnt -= 2;
358
359 if (count++ > 0x800) {
360 spin_wheel();
361 count = 0;
362 }
363 }
364 /* handle word aligned part */
365 if (cnt) {
366 /* handle word aligned part */
367 count = 0;
368 data = *((FPWV *) wp);
369
370 data = (data & 0x00FF) | (*src << 8);
371
372 if ((rc = write_word(info, (FPWV *) wp, data)) != 0)
373 return (rc);
374
375 wp++;
376 src++;
377 cnt -= 1;
378 if (count++ > 0x800) {
379 spin_wheel();
380 count = 0;
381 }
382 }
383
384 if (cnt == 0)
385 return ERR_OK;
386
387 return ERR_OK;
388}
389
390/*-----------------------------------------------------------------------
391 * Write a word to Flash
392 * A word is 16 bits, whichever the bus width of the flash bank
393 * (not an individual chip) is.
394 *
395 * returns:
396 * 0 - OK
397 * 1 - write timeout
398 * 2 - Flash not erased
399 */
400int write_word(flash_info_t * info, FPWV * dest, u16 data)
401{
402 ulong start;
403 int flag;
404 int res = 0; /* result, assume success */
405 FPWV *base; /* first address in flash bank */
406
407 /* Check if Flash is (sufficiently) erased */
408 if ((*dest & (u8) data) != (u8) data) {
409 return (2);
410 }
411
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200412 base = (FPWV *) (CONFIG_SYS_FLASH_BASE);
TsiChung Liewdd8513c2008-07-23 17:11:47 -0500413
414 /* Disable interrupts which might cause a timeout here */
415 flag = disable_interrupts();
416
417 base[FLASH_CYCLE1] = (u8) 0x00AA00AA; /* unlock */
418 base[FLASH_CYCLE2] = (u8) 0x00550055; /* unlock */
419 base[FLASH_CYCLE1] = (u8) 0x00A000A0; /* selects program mode */
420
421 *dest = data; /* start programming the data */
422
423 /* re-enable interrupts if necessary */
424 if (flag)
425 enable_interrupts();
426
427 start = get_timer(0);
428
429 /* data polling for D7 */
430 while (res == 0
431 && (*dest & (u8) 0x00800080) != (data & (u8) 0x00800080)) {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200432 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
TsiChung Liewdd8513c2008-07-23 17:11:47 -0500433 *dest = (u8) 0x00F000F0; /* reset bank */
434 res = 1;
435 }
436 }
437
438 *dest++ = (u8) 0x00F000F0; /* reset bank */
439
440 return (res);
441}
442
Tom Rini03183832017-05-08 22:14:35 -0400443static inline void spin_wheel(void)
TsiChung Liewdd8513c2008-07-23 17:11:47 -0500444{
445 static int p = 0;
446 static char w[] = "\\/-";
447
448 printf("\010%c", w[p]);
449 (++p == 3) ? (p = 0) : 0;
450}
451
452#endif