]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/ebsa285/v2_0/support/linux/safl_util/sa_flash.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / ebsa285 / v2_0 / support / linux / safl_util / sa_flash.c
1
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <fcntl.h>
6 #include <errno.h>
7 #include <sys/mman.h>
8 #include <sys/ioctl.h>
9
10 #define FLASH_SZ (4 * 1024 * 1024)
11 #define FLASH_BLOCK_SZ (256 * 1024)
12
13 volatile void *flash_base;
14 int  driver_fd;
15
16 /* 
17  * sync PCI transactions
18  */
19 static void
20 pci_sync(void)
21 {
22     volatile unsigned int x;
23
24     x = *(unsigned int *)flash_base;
25 }
26
27 static void
28 flash_write_mode(void)
29 {
30     pci_sync();
31     *(volatile int *)flash_base = 0x40404040;
32 }
33
34
35 static void
36 flash_normal_mode(void)
37 {
38     pci_sync();
39     *(volatile int *)flash_base = 0xffffffff;
40 }
41
42
43 /*
44  *  Check to see if there is some flash at the location specified.
45  */
46 static int
47 flash_verify(void) 
48 {
49     volatile unsigned int *fp = (volatile unsigned int *)flash_base; 
50     unsigned int mfg, id ;
51
52     flash_normal_mode();
53
54     /* read the manufacturer's id. */
55     pci_sync();
56     *fp = 0x90909090;
57     mfg = *fp;
58
59     if (mfg != 0x89898989) {
60         flash_normal_mode();
61         return 0;
62     } 
63
64     id = *(fp + 1) ;
65
66     flash_normal_mode();
67
68     if (id < 0xA1A1A1A1)
69         return 0;
70
71     return 1;
72 }
73
74
75 static unsigned int
76 flash_read_dword(int offset)
77 {
78     /* swap initial 32 byte blocks when accessing flash from PCI */
79     if (offset < 32)
80         offset += 32;
81     else if (offset < 64)
82         offset -= 32;
83
84     offset &= ~3;  /* dword alignment */
85
86     return *(volatile unsigned int *)(flash_base + offset);
87 }
88
89
90 static int
91 flash_write_dword(int offset, unsigned int data) 
92
93     volatile unsigned int *fp; 
94     int status;
95
96     /* swap initial 32 byte blocks when accessing flash from PCI */
97     if (offset < 32)
98         offset += 32;
99     else if (offset < 64)
100         offset -= 32;
101
102     offset &= ~3;  /* dword alignment */
103
104     fp = (volatile unsigned int *)(flash_base + offset) ;
105
106     flash_write_mode();
107   
108     /* write the data */
109     *fp = data;
110
111     /* wait till done */
112     do {
113         pci_sync();
114         *fp = 0x70707070;
115         status = *fp;
116     } while ((status & 0x80808080) != 0x80808080);
117   
118     *fp = 0x50505050; /* Clear status register */
119     flash_normal_mode();
120
121     if ( (status & 0x02020202) != 0) {
122         fprintf(stderr,"WRITE LOCKED %08x :", status);
123         return 0;
124     }
125     if ( (status & 0x10101010) != 0) {
126         fprintf(stderr,"WRITE FAILURE %08x :", status);
127         return 0;
128     }
129     return 1;
130 }
131
132
133 static int
134 flash_erase_block(int block) 
135 {
136     volatile unsigned int *fp;
137     int status;
138
139     fp = (volatile unsigned int *)(flash_base + (block * FLASH_BLOCK_SZ));
140
141     /* write delete block command followed by confirm */
142     pci_sync();
143     *fp = 0x20202020;
144     pci_sync();
145     *fp = 0xd0d0d0d0;
146
147     /* wait till done */
148     do {
149         pci_sync();
150         *fp = 0x70707070;
151         status = *fp;
152     } while ((status & 0x80808080) != 0x80808080);
153   
154     *fp = 0x50505050; /* Clear status register */
155     flash_normal_mode();
156
157     if ( (status & 0x02020202) != 0) {
158         fprintf(stderr,"ERASE LOCKED %08x :", status);
159         return 0;
160     }
161     if ( (status & 0x20202020) != 0) {
162         fprintf(stderr,"ERASE FAILURE %08x :", status);
163         return 0;
164     }
165
166     return 1;
167 }
168
169
170 int
171 main(int argc, char *argv[])
172 {
173     int in_fd = STDIN_FILENO, i=0, got, offset, extra;
174     int buf[256];
175     int fw = 1, fv = 1, fr = 0, verbose = 0;
176     char *name = NULL;
177     int block = 0;
178
179     if ( argc > 2 ) {
180         if ( '-' == argv[1][0] && 'b' == argv[1][1] && 0 == argv[1][3] ) {
181             char c = argv[1][2];
182             if (      '0' <= c && c <= '9') block = c - '0';
183             else if ( 'a' <= c && c <= 'f') block = c - 'a' + 10;
184             else if ( 'A' <= c && c <= 'F') block = c - 'A' + 10;
185             else argc = 1; /* get usage message below */
186             argv++, argc--;
187         }
188     }
189
190     switch (argc) {
191     case 1:
192         in_fd = STDIN_FILENO;
193         fv = 0; /* Cannot rewind stdin, so do not verify */
194         break;
195     case 2:
196         if ( '-' == argv[1][0] ) {
197             if ( 'r' != argv[1][1] || 0 != argv[1][2]) goto usage;
198             fr = 1;
199             fw = fv = 0;
200             break;
201         }
202         name = argv[1];
203         in_fd = open(argv[1], O_RDONLY);
204         if (in_fd < 0) {
205             fprintf(stderr, "Can't open %s", argv[1]);
206             perror(": ");
207             exit(1);
208         }
209         break;
210     case 3:
211         if ( '-' != argv[1][0] || 0 != argv[1][2]) goto usage;
212         if (      'v' == argv[1][1] )              fw = 0;
213         else if ( 'V' == argv[1][1] )              fw = 0, verbose = 1;
214         else if ( 'w' == argv[1][1] )              fv = 0;
215         else                                       goto usage;
216
217         name = argv[2];
218         in_fd = open(argv[2], O_RDONLY);
219         if (in_fd < 0) {
220             fprintf(stderr, "Can't open %s", argv[2]);
221             perror(": ");
222             exit(1);
223         }
224         break;
225     default:
226     usage:
227         fprintf(stderr, "Usage:          sa_flash [filename]\n");
228         fprintf(stderr, "Block number:   sa_flash -bN [filename]\n");
229         fprintf(stderr, "Write only:     sa_flash [-bN] -w    filename\n");
230         fprintf(stderr, "Verify only:    sa_flash [-bN] -v|-V filename\n");
231         fprintf(stderr, "Read to stdout: sa_flash [-bN] -r\n");
232         exit(1);
233     }
234
235     driver_fd = open("/dev/safl", O_RDWR);
236     if (driver_fd < 0) {
237         perror("Can't open device: ");
238         exit (1);
239     }
240
241     flash_base = mmap(NULL, FLASH_SZ, PROT_READ|PROT_WRITE,
242                       MAP_SHARED, driver_fd, 0);
243
244     if (flash_base == NULL) {
245         perror("mmap failed: ");
246         close(driver_fd);
247         return 0;
248     }
249
250     if (!flash_verify()) {
251         fprintf(stderr, "Couldn't find flash.\n");
252         exit(1);
253     }
254     
255     if ( fw ) {
256         if ( ! flash_erase_block(block) ) {
257             fprintf(stderr,"Erase error block %x\n", block);
258             exit(1);
259         }
260
261         extra = 0;
262         offset = block * FLASH_BLOCK_SZ;
263         while ((got = read(in_fd, ((char *)buf) + extra, sizeof(buf) - extra)) > 0) {
264             got += extra;
265
266             extra = got & 3;
267             got /= 4;
268             for (i = 0; i < got; ++i, offset += 4)
269                 if ( ! flash_write_dword(offset, buf[i]) )
270                     fprintf(stderr,"Write error offset %06x\n",offset);
271
272             if (extra)
273                 buf[0] = buf[i];
274
275             printf("*"); fflush(stdout);
276         }
277         if (extra)
278             if ( ! flash_write_dword(offset, buf[i]) )
279                 fprintf(stderr,"Write error offset %06x\n",offset);
280         printf("\n");
281     }
282
283     flash_normal_mode();
284
285     if ( fv ) {
286         int badwords = 0;
287         int skipping = 0;
288         close( in_fd );
289         in_fd = open(name, O_RDONLY);
290         if (in_fd < 0) {
291             fprintf(stderr, "Can't re-open %s", argv[2]);
292             perror(": ");
293             exit(1);
294         }
295
296         extra = 0;
297         offset = block * FLASH_BLOCK_SZ;
298         while ((got = read(in_fd, ((char *)buf) + extra, sizeof(buf) - extra)) > 0) {
299             got += extra;
300
301             extra = got & 3;
302             got /= 4;
303             for (i = 0; i < got; ++i, offset += 4) {
304                 int data = flash_read_dword(offset);
305                 if ( data != buf[i] ) {
306                     badwords++;
307                     if ( !skipping ) {
308                         fprintf(stderr, "Bad data at offset %06x: %08x read %08x wanted\n",
309                                 offset, data, buf[i] );
310                         if ( !verbose && badwords > 15 ) {
311                             skipping = 1;
312                             fprintf(stderr, "(Too many errors, skipping...)\n");
313                         }
314                     }
315                 }
316             }
317             if (extra)
318                 buf[0] = buf[i];
319
320             printf("+"); fflush(stdout);
321         }
322         if (extra) {
323             int data = flash_read_dword(offset);
324             if ( data != buf[0] ) {
325                 fprintf(stderr, "End data at offset %06x: %08x read %08x wanted\n",
326                         offset, data, buf[0] );
327             }
328         }
329         printf("\n");
330         if ( badwords )
331             fprintf(stderr, "Bad data: %d bad words out of %d (end offset %06x)\n",
332                     badwords, offset/4, offset );
333     }
334
335     flash_normal_mode();
336
337     if ( fr ) {
338         for ( offset = block * FLASH_BLOCK_SZ;
339               offset < (block+1) * FLASH_BLOCK_SZ;
340               offset += 4 ) {
341             for ( i = 0; i < (sizeof(buf)/sizeof(int)); ++i, offset += 4 ) {
342                 buf[i] = flash_read_dword(offset);
343             }
344             if ( sizeof(buf) != write( STDOUT_FILENO, buf, sizeof(buf) ) ) {
345                 perror("Stdout write failed: ");
346                 exit(1);
347             }
348             fprintf(stderr,"r");
349             fflush(stderr);
350         }
351         fprintf(stderr,"\n");
352     }
353
354     munmap((void *)flash_base, FLASH_SZ);
355     close(driver_fd);
356     return 0;
357 }
358
359
360
361 \f
362 /*
363  * Local variables:
364  *  compile-command: "cc -g -O2 -Wall sa_flash.c -o sa_flash"
365  * End:
366  */