Prepare v2023.10
[platform/kernel/u-boot.git] / board / freescale / m5253demo / flash.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
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)
8  */
9
10 #include <common.h>
11 #include <flash.h>
12 #include <init.h>
13 #include <irq_func.h>
14
15 #include <asm/immap.h>
16
17 #ifndef CONFIG_SYS_FLASH_CFI
18 typedef unsigned short FLASH_PORT_WIDTH;
19 typedef volatile unsigned short FLASH_PORT_WIDTHV;
20
21 #define FPW             FLASH_PORT_WIDTH
22 #define FPWV            FLASH_PORT_WIDTHV
23
24 #define FLASH_CYCLE1    0x5555
25 #define FLASH_CYCLE2    0x2aaa
26
27 #define SYNC                    __asm__("nop")
28
29 /*-----------------------------------------------------------------------
30  * Functions
31  */
32
33 ulong flash_get_size(FPWV * addr, flash_info_t * info);
34 int flash_get_offsets(ulong base, flash_info_t * info);
35 int write_word(flash_info_t * info, FPWV * dest, u16 data);
36 static inline void spin_wheel(void);
37
38 flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
39
40 ulong flash_init(void)
41 {
42         ulong size = 0;
43         ulong fbase = 0;
44
45         fbase = (ulong) CFG_SYS_FLASH_BASE;
46         flash_get_size((FPWV *) fbase, &flash_info[0]);
47         flash_get_offsets((ulong) fbase, &flash_info[0]);
48         fbase += flash_info[0].size;
49         size += flash_info[0].size;
50
51         /* Protect monitor and environment sectors */
52         flash_protect(FLAG_PROTECT_SET,
53                       CONFIG_SYS_MONITOR_BASE,
54                       CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, &flash_info[0]);
55
56         return size;
57 }
58
59 int flash_get_offsets(ulong base, flash_info_t * info)
60 {
61         int i;
62
63         if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
64
65                 info->start[0] = base;
66                 info->protect[0] = 0;
67                 for (i = 1; i < CFG_SYS_SST_SECT; i++) {
68                         info->start[i] = info->start[i - 1]
69                                                 + CFG_SYS_SST_SECTSZ;
70                         info->protect[i] = 0;
71                 }
72         }
73
74         return ERR_OK;
75 }
76
77 void flash_print_info(flash_info_t * info)
78 {
79         int i;
80
81         switch (info->flash_id & FLASH_VENDMASK) {
82         case FLASH_MAN_SST:
83                 printf("SST ");
84                 break;
85         default:
86                 printf("Unknown Vendor ");
87                 break;
88         }
89
90         switch (info->flash_id & FLASH_TYPEMASK) {
91         case FLASH_SST6401B:
92                 printf("SST39VF6401B\n");
93                 break;
94         default:
95                 printf("Unknown Chip Type\n");
96                 return;
97         }
98
99         printf("  Size: %ld KB in %d Sectors\n",
100                info->size >> 10, info->sector_count);
101
102         printf("  Sector Start Addresses:");
103         for (i = 0; i < info->sector_count; ++i) {
104                 if ((i % 5) == 0)
105                         printf("\n   ");
106                 printf(" %08lX%s",
107                        info->start[i], info->protect[i] ? " (RO)" : "     ");
108         }
109         printf("\n");
110 }
111
112 /*
113  * The following code cannot be run from FLASH!
114  */
115 ulong flash_get_size(FPWV * addr, flash_info_t * info)
116 {
117         u16 value;
118
119         addr[FLASH_CYCLE1] = (FPWV) 0x00AA00AA; /* for Atmel, Intel ignores this */
120         addr[FLASH_CYCLE2] = (FPWV) 0x00550055; /* for Atmel, Intel ignores this */
121         addr[FLASH_CYCLE1] = (FPWV) 0x00900090; /* selects Intel or Atmel */
122
123         switch (addr[0] & 0xffff) {
124         case (u8) SST_MANUFACT:
125                 info->flash_id = FLASH_MAN_SST;
126                 value = addr[1];
127                 break;
128         default:
129                 printf("Unknown Flash\n");
130                 info->flash_id = FLASH_UNKNOWN;
131                 info->sector_count = 0;
132                 info->size = 0;
133
134                 *addr = (FPW) 0x00F000F0;
135                 return (0);     /* no or unknown flash  */
136         }
137
138         switch (value) {
139         case (u16) SST_ID_xF6401B:
140                 info->flash_id += FLASH_SST6401B;
141                 break;
142         default:
143                 info->flash_id = FLASH_UNKNOWN;
144                 break;
145         }
146
147         info->sector_count = 0;
148         info->size = 0;
149         info->sector_count = CFG_SYS_SST_SECT;
150         info->size = CFG_SYS_SST_SECT * CFG_SYS_SST_SECTSZ;
151
152         /* reset ID mode */
153         *addr = (FPWV) 0x00F000F0;
154
155         if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) {
156                 printf("** ERROR: sector count %d > max (%d) **\n",
157                        info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
158                 info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
159         }
160
161         return (info->size);
162 }
163
164 int flash_erase(flash_info_t * info, int s_first, int s_last)
165 {
166         FPWV *addr;
167         int flag, prot, sect, count;
168         ulong type, start;
169         int rcode = 0, flashtype = 0;
170
171         if ((s_first < 0) || (s_first > s_last)) {
172                 if (info->flash_id == FLASH_UNKNOWN)
173                         printf("- missing\n");
174                 else
175                         printf("- no sectors to erase\n");
176                 return 1;
177         }
178
179         type = (info->flash_id & FLASH_VENDMASK);
180
181         switch (type) {
182         case FLASH_MAN_SST:
183                 flashtype = 1;
184                 break;
185         default:
186                 type = (info->flash_id & FLASH_VENDMASK);
187                 printf("Can't erase unknown flash type %08lx - aborted\n",
188                        info->flash_id);
189                 return 1;
190         }
191
192         prot = 0;
193         for (sect = s_first; sect <= s_last; ++sect) {
194                 if (info->protect[sect]) {
195                         prot++;
196                 }
197         }
198
199         if (prot)
200                 printf("- Warning: %d protected sectors will not be erased!\n",
201                        prot);
202         else
203                 printf("\n");
204
205         flag = disable_interrupts();
206
207         start = get_timer(0);
208
209         if ((s_last - s_first) == (CFG_SYS_SST_SECT - 1)) {
210                 if (prot == 0) {
211                         addr = (FPWV *) info->start[0];
212
213                         addr[FLASH_CYCLE1] = 0x00AA;    /* unlock */
214                         addr[FLASH_CYCLE2] = 0x0055;    /* unlock */
215                         addr[FLASH_CYCLE1] = 0x0080;    /* erase mode */
216                         addr[FLASH_CYCLE1] = 0x00AA;    /* unlock */
217                         addr[FLASH_CYCLE2] = 0x0055;    /* unlock */
218                         *addr = 0x0030; /* erase chip */
219
220                         count = 0;
221                         start = get_timer(0);
222
223                         while ((*addr & 0x0080) != 0x0080) {
224                                 if (count++ > 0x10000) {
225                                         spin_wheel();
226                                         count = 0;
227                                 }
228
229                                 /* check timeout, 1000ms */
230                                 if (get_timer(start) > 1000) {
231                                         printf("Timeout\n");
232                                         *addr = 0x00F0; /* reset to read mode */
233
234                                         return 1;
235                                 }
236                         }
237
238                         *addr = 0x00F0; /* reset to read mode */
239
240                         printf("\b. done\n");
241
242                         if (flag)
243                                 enable_interrupts();
244
245                         return 0;
246                 } else if (prot == CFG_SYS_SST_SECT) {
247                         return 1;
248                 }
249         }
250
251         /* Start erase on unprotected sectors */
252         for (sect = s_first; sect <= s_last; sect++) {
253                 if (info->protect[sect] == 0) { /* not protected */
254
255                         addr = (FPWV *) (info->start[sect]);
256
257                         printf(".");
258
259                         /* arm simple, non interrupt dependent timer */
260                         start = get_timer(0);
261
262                         switch (flashtype) {
263                         case 1:
264                                 {
265                                         FPWV *base;     /* first address in bank */
266
267                                         flag = disable_interrupts();
268
269                                         base = (FPWV *) (CFG_SYS_FLASH_BASE);   /* First sector */
270
271                                         base[FLASH_CYCLE1] = 0x00AA;    /* unlock */
272                                         base[FLASH_CYCLE2] = 0x0055;    /* unlock */
273                                         base[FLASH_CYCLE1] = 0x0080;    /* erase mode */
274                                         base[FLASH_CYCLE1] = 0x00AA;    /* unlock */
275                                         base[FLASH_CYCLE2] = 0x0055;    /* unlock */
276                                         *addr = 0x0050; /* erase sector */
277
278                                         if (flag)
279                                                 enable_interrupts();
280
281                                         while ((*addr & 0x0080) != 0x0080) {
282                                                 /* check timeout, 1000ms */
283                                                 if (get_timer(start) > 1000) {
284                                                         printf("Timeout\n");
285                                                         *addr = 0x00F0; /* reset to read mode */
286
287                                                         rcode = 1;
288                                                         break;
289                                                 }
290                                         }
291
292                                         *addr = 0x00F0; /* reset to read mode */
293                                         break;
294                                 }
295                         }       /* switch (flashtype) */
296                 }
297         }
298         printf(" done\n");
299
300         if (flag)
301                 enable_interrupts();
302
303         return rcode;
304 }
305
306 int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt)
307 {
308         ulong wp, count;
309         u16 data;
310         int rc;
311
312         if (info->flash_id == FLASH_UNKNOWN)
313                 return 4;
314
315         /* get lower word aligned address */
316         wp = addr;
317
318         /* handle unaligned start bytes */
319         if (wp & 1) {
320                 data = *((FPWV *) wp);
321                 data = (data << 8) | *src;
322
323                 if ((rc = write_word(info, (FPWV *) wp, data)) != 0)
324                         return (rc);
325
326                 wp++;
327                 cnt -= 1;
328                 src++;
329         }
330
331         while (cnt >= 2) {
332                 /*
333                  * handle word aligned part
334                  */
335                 count = 0;
336                 data = *((FPWV *) src);
337
338                 if ((rc = write_word(info, (FPWV *) wp, data)) != 0)
339                         return (rc);
340
341                 wp += 2;
342                 src += 2;
343                 cnt -= 2;
344
345                 if (count++ > 0x800) {
346                         spin_wheel();
347                         count = 0;
348                 }
349         }
350         /* handle word aligned part */
351         if (cnt) {
352                 /* handle word aligned part */
353                 count = 0;
354                 data = *((FPWV *) wp);
355
356                 data = (data & 0x00FF) | (*src << 8);
357
358                 if ((rc = write_word(info, (FPWV *) wp, data)) != 0)
359                         return (rc);
360
361                 wp++;
362                 src++;
363                 cnt -= 1;
364                 if (count++ > 0x800) {
365                         spin_wheel();
366                         count = 0;
367                 }
368         }
369
370         if (cnt == 0)
371                 return ERR_OK;
372
373         return ERR_OK;
374 }
375
376 /*-----------------------------------------------------------------------
377  * Write a word to Flash
378  * A word is 16 bits, whichever the bus width of the flash bank
379  * (not an individual chip) is.
380  *
381  * returns:
382  * 0 - OK
383  * 1 - write timeout
384  * 2 - Flash not erased
385  */
386 int write_word(flash_info_t * info, FPWV * dest, u16 data)
387 {
388         ulong start;
389         int flag;
390         int res = 0;            /* result, assume success */
391         FPWV *base;             /* first address in flash bank */
392
393         /* Check if Flash is (sufficiently) erased */
394         if ((*dest & (u8) data) != (u8) data) {
395                 return (2);
396         }
397
398         base = (FPWV *) (CFG_SYS_FLASH_BASE);
399
400         /* Disable interrupts which might cause a timeout here */
401         flag = disable_interrupts();
402
403         base[FLASH_CYCLE1] = (u8) 0x00AA00AA;   /* unlock */
404         base[FLASH_CYCLE2] = (u8) 0x00550055;   /* unlock */
405         base[FLASH_CYCLE1] = (u8) 0x00A000A0;   /* selects program mode */
406
407         *dest = data;           /* start programming the data */
408
409         /* re-enable interrupts if necessary */
410         if (flag)
411                 enable_interrupts();
412
413         start = get_timer(0);
414
415         /* data polling for D7 */
416         while (res == 0
417                && (*dest & (u8) 0x00800080) != (data & (u8) 0x00800080)) {
418                 /* check timeout, 500ms */
419                 if (get_timer(start) > 500) {
420                         *dest = (u8) 0x00F000F0;        /* reset bank */
421                         res = 1;
422                 }
423         }
424
425         *dest++ = (u8) 0x00F000F0;      /* reset bank */
426
427         return (res);
428 }
429
430 static inline void spin_wheel(void)
431 {
432         static int p = 0;
433         static char w[] = "\\/-";
434
435         printf("\010%c", w[p]);
436         (++p == 3) ? (p = 0) : 0;
437 }
438
439 #endif