]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/eltec/mhpc/flash.c
gic: fixed compilation error in GICv2 wait for interrupt macro
[karo-tx-uboot.git] / board / eltec / mhpc / flash.c
1 /*
2  * (C) Copyright 2001
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9 #include <mpc8xx.h>
10 #include <linux/byteorder/swab.h>
11
12 flash_info_t    flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
13
14 /*-----------------------------------------------------------------------
15  * Protection Flags:
16  */
17 #define FLAG_PROTECT_SET        0x01
18 #define FLAG_PROTECT_CLEAR      0x02
19
20 /* Board support for 1 or 2 flash devices */
21 #undef FLASH_PORT_WIDTH32
22 #define FLASH_PORT_WIDTH16
23
24 #ifdef FLASH_PORT_WIDTH16
25 #define FLASH_PORT_WIDTH                ushort
26 #define FLASH_PORT_WIDTHV               vu_short
27 #define SWAP(x)                         __swab16(x)
28 #else
29 #define FLASH_PORT_WIDTH                ulong
30 #define FLASH_PORT_WIDTHV               vu_long
31 #define SWAP(x)                         __swab32(x)
32 #endif
33
34 #define FPW     FLASH_PORT_WIDTH
35 #define FPWV    FLASH_PORT_WIDTHV
36
37 /*-----------------------------------------------------------------------
38  * Functions
39  */
40 static ulong flash_get_size (FPW *addr, flash_info_t *info);
41 static int   write_data (flash_info_t *info, ulong dest, FPW data);
42 static void  flash_get_offsets (ulong base, flash_info_t *info);
43
44 /*-----------------------------------------------------------------------
45  */
46
47 unsigned long flash_init (void)
48 {
49         volatile immap_t     *immap  = (immap_t *)CONFIG_SYS_IMMR;
50         volatile memctl8xx_t *memctl = &immap->im_memctl;
51         unsigned long size_b0;
52         int i;
53
54         /* Init: no FLASHes known */
55         for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
56                 flash_info[i].flash_id = FLASH_UNKNOWN;
57         }
58
59         /* Static FLASH Bank configuration here - FIXME XXX */
60         size_b0 = flash_get_size((FPW *)FLASH_BASE0_PRELIM, &flash_info[0]);
61
62         if (flash_info[0].flash_id == FLASH_UNKNOWN) {
63                 printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
64                         size_b0, size_b0<<20);
65         }
66
67         /* Remap FLASH according to real size */
68         memctl->memc_or0 = CONFIG_SYS_OR_TIMING_FLASH | (-size_b0 & 0xFFFF8000);
69         memctl->memc_br0 = (CONFIG_SYS_FLASH_BASE & BR_BA_MSK) | BR_PS_16 | BR_MS_GPCM | BR_V;
70
71         /* Re-do sizing to get full correct info */
72         size_b0 = flash_get_size((FPW *)CONFIG_SYS_FLASH_BASE, &flash_info[0]);
73
74         flash_get_offsets (CONFIG_SYS_FLASH_BASE, &flash_info[0]);
75
76         /* monitor protection ON by default */
77         (void)flash_protect(FLAG_PROTECT_SET,
78                             CONFIG_SYS_FLASH_BASE,
79                             CONFIG_SYS_FLASH_BASE+monitor_flash_len-1,
80                             &flash_info[0]);
81
82         flash_info[0].size = size_b0;
83
84         return (size_b0);
85 }
86
87 /*-----------------------------------------------------------------------
88  */
89 static void flash_get_offsets (ulong base, flash_info_t *info)
90 {
91         int i;
92
93         if (info->flash_id == FLASH_UNKNOWN) {
94                 return;
95         }
96
97         if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
98                 for (i = 0; i < info->sector_count; i++) {
99                         info->start[i] = base + (i * 0x00020000);
100                 }
101         }
102 }
103
104 /*-----------------------------------------------------------------------
105  */
106 void flash_print_info  (flash_info_t *info)
107 {
108         int i;
109
110         if (info->flash_id == FLASH_UNKNOWN) {
111                 printf ("missing or unknown FLASH type\n");
112                 return;
113         }
114
115         switch (info->flash_id & FLASH_VENDMASK) {
116                 case FLASH_MAN_INTEL:   printf ("INTEL ");              break;
117                 default:                printf ("Unknown Vendor ");     break;
118         }
119
120         switch (info->flash_id & FLASH_TYPEMASK) {
121    case FLASH_28F640J5 :
122                                 printf ("28F640J5 \n"); break;
123         default:                printf ("Unknown Chip Type=0x%lXh\n",
124                                         info->flash_id & FLASH_TYPEMASK); break;
125         }
126
127         printf ("  Size: %ld MB in %d Sectors\n",
128                 info->size >> 20, info->sector_count);
129
130         printf ("  Sector Start Addresses:");
131         for (i=0; i<info->sector_count; ++i) {
132                 if ((i % 5) == 0)
133                         printf ("\n   ");
134                 printf (" %08lX%s",
135                         info->start[i],
136                         info->protect[i] ? " (RO)" : "     "
137                 );
138         }
139         printf ("\n");
140 }
141
142 /*-----------------------------------------------------------------------
143  */
144
145
146 /*-----------------------------------------------------------------------
147  */
148
149 /*
150  * The following code cannot be run from FLASH!
151  */
152
153 static ulong flash_get_size (FPW *addr, flash_info_t *info)
154 {
155         FPW value;
156
157         /* Write auto select command: read Manufacturer ID */
158         addr[0x5555] = (FPW)0xAA00AA00;
159         addr[0x2AAA] = (FPW)0x55005500;
160         addr[0x5555] = (FPW)0x90009000;
161
162         value = SWAP(addr[0]);
163
164    switch (value) {
165    case (FPW)INTEL_MANUFACT:
166       info->flash_id = FLASH_MAN_INTEL;
167       break;
168         default:
169                 info->flash_id = FLASH_UNKNOWN;
170                 info->sector_count = 0;
171                 info->size = 0;
172                 addr[0] = (FPW)0xFF00FF00;      /* restore read mode */
173                 return (0);                           /* no or unknown flash    */
174         }
175
176    value = SWAP(addr[1]);                               /* device ID no swap !*/
177
178    switch (value) {
179    case (FPW)INTEL_ID_28F640J5 :
180         info->flash_id += FLASH_28F640J5 ;
181         info->sector_count = 64;
182         info->size = 0x00800000;
183         break;            /* => 8 MB     */
184
185         default:
186                 info->flash_id = FLASH_UNKNOWN;
187                 break;
188         }
189
190         if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) {
191                 printf ("** ERROR: sector count %d > max (%d) **\n",
192                         info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
193                 info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
194         }
195
196         addr[0] = (FPW)0xFF00FF00;      /* restore read mode */
197
198         return (info->size);
199 }
200
201
202 /*-----------------------------------------------------------------------
203  */
204
205 int     flash_erase (flash_info_t *info, int s_first, int s_last)
206 {
207         int flag, prot, sect;
208         ulong type, start, now, last;
209         int rc = 0;
210
211         if ((s_first < 0) || (s_first > s_last)) {
212                 if (info->flash_id == FLASH_UNKNOWN) {
213                         printf ("- missing\n");
214                 } else {
215                         printf ("- no sectors to erase\n");
216                 }
217                 return 1;
218         }
219
220         type = (info->flash_id & FLASH_VENDMASK);
221         if ((type != FLASH_MAN_INTEL)) {
222                 printf ("Can't erase unknown flash type %08lx - aborted\n",
223                         info->flash_id);
224                 return 1;
225         }
226
227         prot = 0;
228         for (sect=s_first; sect<=s_last; ++sect) {
229                 if (info->protect[sect]) {
230                         prot++;
231                 }
232         }
233
234         if (prot) {
235                 printf ("- Warning: %d protected sectors will not be erased!\n",
236                         prot);
237         } else {
238                 printf ("\n");
239         }
240
241         start = get_timer (0);
242         last  = start;
243         /* Start erase on unprotected sectors */
244         for (sect = s_first; sect<=s_last; sect++) {
245                 if (info->protect[sect] == 0) { /* not protected */
246                         FPWV *addr = (FPWV *)(info->start[sect]);
247                         FPW status;
248
249                         /* Disable interrupts which might cause a timeout here */
250                         flag = disable_interrupts();
251
252                         *addr = (FPW)0x50005000;        /* clear status register */
253                         *addr = (FPW)0x20002000;        /* erase setup */
254                         *addr = (FPW)0xD000D000;        /* erase confirm */
255
256                         /* re-enable interrupts if necessary */
257                         if (flag)
258                                 enable_interrupts();
259
260                         /* wait at least 80us - let's wait 1 ms */
261                         udelay (1000);
262
263                         while (((status = SWAP(*addr)) & (FPW)0x00800080) != (FPW)0x00800080) {
264                                 if ((now=get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
265                                         printf ("Timeout\n");
266                                         *addr = (FPW)0xB000B000; /* suspend erase */
267                                         *addr = (FPW)0xFF00FF00; /* reset to read mode */
268                                         rc = 1;
269                                         break;
270                                 }
271
272                                 /* show that we're waiting */
273                         if ((now - last) > 1000) {      /* every second */
274                                         putc ('.');
275                                         last = now;
276                                 }
277                         }
278
279                         *addr = (FPW)0xFF00FF00;        /* reset to read mode */
280                         printf (" done\n");
281                 }
282         }
283         return rc;
284 }
285
286 /*-----------------------------------------------------------------------
287  * Copy memory to flash, returns:
288  * 0 - OK
289  * 1 - write timeout
290  * 2 - Flash not erased
291  * 4 - Flash not identified
292  */
293
294 int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
295 {
296         ulong cp, wp;
297         FPW data;
298         int i, l, rc, port_width;
299
300         if (info->flash_id == FLASH_UNKNOWN) {
301                 return 4;
302         }
303 /* get lower word aligned address */
304 #ifdef FLASH_PORT_WIDTH16
305         wp = (addr & ~1);
306         port_width = 2;
307 #else
308         wp = (addr & ~3);
309         port_width = 4;
310 #endif
311
312         /*
313          * handle unaligned start bytes
314          */
315         if ((l = addr - wp) != 0) {
316                 data = 0;
317                 for (i=0, cp=wp; i<l; ++i, ++cp)
318                         data = (data << 8) | (*(uchar *)cp);
319
320                 for (; i<port_width && cnt>0; ++i) {
321                         data = (data << 8) | *src++;
322                         --cnt;
323                         ++cp;
324                 }
325                 for (; cnt==0 && i<port_width; ++i, ++cp) {
326                         data = (data << 8) | (*(uchar *)cp);
327                 }
328
329                 if ((rc = write_data(info, wp, data)) != 0) {
330                         return (rc);
331                 }
332                 wp += port_width;
333         }
334
335         /*
336          * handle word aligned part
337          */
338         while (cnt >= port_width) {
339                 data = 0;
340                 for (i=0; i<port_width; ++i) {
341                         data = (data << 8) | *src++;
342                 }
343                 if ((rc = write_data(info, wp, data)) != 0) {
344                         return (rc);
345                 }
346                 wp  += port_width;
347                 cnt -= port_width;
348                 if ((wp & 0xfff) == 0)
349                 {
350                         printf("%08lX",wp);
351                         printf("\x1b[8D");
352                 }
353         }
354
355         if (cnt == 0) {
356                 return (0);
357         }
358
359         /*
360          * handle unaligned tail bytes
361          */
362         data = 0;
363         for (i=0, cp=wp; i<port_width && cnt>0; ++i, ++cp) {
364                 data = (data << 8) | *src++;
365                 --cnt;
366         }
367         for (; i<port_width; ++i, ++cp) {
368                 data = (data << 8) | (*(uchar *)cp);
369         }
370
371         return (write_data(info, wp, data));
372 }
373
374 /*-----------------------------------------------------------------------
375  * Write a word or halfword to Flash, returns:
376  * 0 - OK
377  * 1 - write timeout
378  * 2 - Flash not erased
379  */
380 static int write_data (flash_info_t *info, ulong dest, FPW data)
381 {
382         FPWV *addr = (FPWV *)dest;
383         ulong status;
384         ulong start;
385         int flag;
386
387         /* Check if Flash is (sufficiently) erased */
388         if ((*addr & data) != data) {
389                 printf("not erased at %08lx (%x)\n",(ulong)addr,*addr);
390                 return (2);
391         }
392         /* Disable interrupts which might cause a timeout here */
393         flag = disable_interrupts();
394
395         *addr = (FPW)0x40004000;                /* write setup */
396         *addr = data;
397
398         /* re-enable interrupts if necessary */
399         if (flag)
400                 enable_interrupts();
401
402         start = get_timer (0);
403
404         while (((status = SWAP(*addr)) & (FPW)0x00800080) != (FPW)0x00800080) {
405                 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
406                         *addr = (FPW)0xFF00FF00;        /* restore read mode */
407                         return (1);
408                 }
409         }
410
411         *addr = (FPW)0xFF00FF00;        /* restore read mode */
412
413         return (0);
414 }