Mercurial > flash_v2
annotate packages/hal/arm/pid/current/misc/flash.c @ 64:c38311975d4f ecos-sw-2000-01-28
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
| author | jlarmour |
|---|---|
| date | Fri, 28 Jan 2000 04:59:39 +0000 |
| parents | 443894e2e912 |
| children | bf00f99aec69 |
| rev | line source |
|---|---|
| 2 | 1 //========================================================================== |
| 2 // | |
| 3 // flash.c | |
| 4 // | |
| 5 // ARM PID7 eval board FLASH program tool | |
| 6 // | |
| 7 //========================================================================== | |
| 8 //####COPYRIGHTBEGIN#### | |
|
64
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
9 // |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
10 // ------------------------------------------- |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
11 // The contents of this file are subject to the Red Hat eCos Public License |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
12 // Version 1.0 (the "License"); you may not use this file except in |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
13 // compliance with the License. You may obtain a copy of the License at |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
14 // http://sourceware.cygnus.com/ecos |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
15 // |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
16 // Software distributed under the License is distributed on an |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
18 // License for the specific language governing rights and limitations under |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
19 // the License. |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
20 // |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
21 // The Original Code is eCos - Embedded Configurable Operating System, |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
22 // released September 30, 1998. |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
23 // |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
24 // The Initial Developer of the Original Code is Red Hat. |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
25 // Portions created by Red Hat are |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
26 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc. |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
27 // All Rights Reserved. |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
28 // ------------------------------------------- |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
2
diff
changeset
|
29 // |
| 2 | 30 //####COPYRIGHTEND#### |
| 31 //========================================================================== | |
| 32 //#####DESCRIPTIONBEGIN#### | |
| 33 // | |
| 34 // Author(s): gthomas | |
| 35 // Contributors: gthomas | |
| 36 // Date: 1998-11-18 | |
| 37 // Description: Tool used to program onboard FLASH image | |
| 38 //####DESCRIPTIONEND#### | |
| 39 | |
| 40 // | |
| 41 // This program will program the FLASH on the PID board | |
| 42 // | |
| 43 | |
| 44 #include <pkgconf/libc.h> // Configuration header | |
| 45 | |
| 46 #include <cyg/kernel/kapi.h> | |
| 47 #include <stdlib.h> | |
| 48 #include <ctype.h> | |
| 49 #include <cyg/infra/testcase.h> | |
| 50 #include <sys/cstartup.h> | |
| 51 | |
| 52 #ifndef FALSE | |
| 53 #define FALSE 0 | |
| 54 #define TRUE 1 | |
| 55 #endif | |
| 56 | |
| 57 #define SYNC_COUNT 63 | |
| 58 | |
| 59 extern void diag_printf(const char *, ...); | |
| 60 int identify_FLASH(void); | |
| 61 void write_sector(int, char *); | |
| 62 bool load_srecords(char (*readc)(), CYG_ADDRESS *start, int *size); | |
| 63 | |
| 64 char dbuf[256]; | |
| 65 char *raw = (char *)0x10000; | |
| 66 char *flash_buffer = (char *)0x30000; | |
| 67 int pos, len; | |
| 68 | |
| 69 // FUNCTIONS | |
| 70 | |
| 71 externC void | |
| 72 cyg_package_start( void ) | |
| 73 { | |
| 74 #ifdef CYGPKG_LIBC | |
| 75 cyg_iso_c_start(); | |
| 76 #else | |
| 77 (void)main(0, NULL); | |
| 78 #endif | |
| 79 } // cyg_package_start() | |
| 80 | |
| 81 char nextch(void) | |
| 82 { | |
| 83 return (raw[pos++]); | |
| 84 } | |
| 85 | |
| 86 int | |
| 87 main( int argc, char *argv[] ) | |
| 88 { | |
| 89 int i, j, size; | |
| 90 CYG_ADDRESS entry; | |
| 91 char c; | |
| 92 diag_printf("FLASH here!\n"); | |
| 93 while (identify_FLASH() == 0) { | |
| 94 diag_printf("... Please change FLASH jumper - hit C/R to continue:"); | |
| 95 do { | |
| 96 hal_diag_read_char(&c); | |
| 97 } while ((c != '\r') && (c != '\n')); | |
| 98 diag_printf("\n"); | |
| 99 } | |
| 100 restart: | |
| 101 diag_printf("Ready file - hit C/R to continue:"); | |
| 102 while (TRUE) { | |
| 103 hal_diag_read_char(&c); | |
| 104 if (c == '>') break; | |
| 105 } | |
| 106 i = 0; j = 0; | |
| 107 while (1) { | |
| 108 hal_diag_read_char(&c); | |
| 109 if (c == '!') { | |
| 110 diag_printf("... Reset\n"); | |
| 111 goto restart; | |
| 112 } | |
| 113 raw[i++] = c; | |
| 114 if (++j == SYNC_COUNT) { | |
| 115 hal_diag_write_char(c); | |
| 116 j = 0; | |
| 117 } | |
| 118 if (c == ':') break; | |
| 119 } | |
| 120 diag_printf("\n"); | |
| 121 pos = 0; len = i; | |
| 122 if (load_srecords(nextch, &entry, &size)) { | |
| 123 diag_printf("Read %x bytes, entry: %x\n", size, entry); | |
| 124 dump_buf(flash_buffer, 128); | |
| 125 diag_printf("\nData loaded - hit '!' to continue:"); | |
| 126 while (TRUE) { | |
| 127 hal_diag_read_char(&c); | |
| 128 if (c == '!') break; | |
| 129 } | |
| 130 diag_printf("\n"); | |
| 131 diag_printf("...Programming FLASH\n"); | |
| 132 pos = 0; i = 0; | |
| 133 while (pos < size) { | |
| 134 write_sector(i++, flash_buffer+pos); | |
| 135 pos += 256; | |
| 136 } | |
| 137 } else { | |
| 138 // Display buffer around failure | |
| 139 dump_buf(&raw[pos-32], 64); | |
| 140 } | |
| 141 diag_printf("All done!\n"); | |
| 142 while (1) ; | |
| 143 } | |
| 144 | |
| 145 // Adapted from ARM sample code | |
| 146 #define SEQ_ADD1 0x5555 | |
| 147 #define SEQ_ADD2 0xAAAA | |
| 148 #define START_CMD1 0xAA | |
| 149 #define START_CMD2 0x55 | |
| 150 #define ID_CMD 0x90 | |
| 151 #define PROG_CMD 0xA0 | |
| 152 #define STOP_CMD 0xF0 | |
| 153 | |
| 154 #define MAN_ATMEL 0x1F | |
| 155 #define ATMEL_AT29C040_ID 0X5B | |
| 156 #define ATMEL_AT29C040A_ID 0XA4 | |
| 157 #define ATMEL_AT29C1024_ID 0X25 | |
| 158 #define ATMEL_SECTOR_SIZE 256 | |
| 159 #define ATMEL_MAX_SECTORS 2048 | |
| 160 | |
| 161 int manuf_code, device_code, sector_size, max_no_of_sectors, word_mode; | |
| 162 volatile char *FLASH = (volatile char *)0x04000000; | |
| 163 | |
| 164 int | |
| 165 identify_FLASH(void ) | |
| 166 { | |
| 167 // Enter Software Product Identification Mode | |
| 168 FLASH[SEQ_ADD1] = START_CMD1; | |
| 169 FLASH[SEQ_ADD2] = START_CMD2; | |
| 170 FLASH[SEQ_ADD1] = ID_CMD; | |
| 171 | |
| 172 // Wait at least 10ms | |
| 173 cyg_thread_delay(2); | |
| 174 | |
| 175 // Read Manufacturer and device code from the device | |
| 176 manuf_code = FLASH[0]; | |
| 177 device_code = FLASH[1]; | |
| 178 | |
| 179 diag_printf("manuf: %x, device: %x\n", manuf_code, device_code); | |
| 180 | |
| 181 // Exit Software Product Identification Mode | |
| 182 FLASH[SEQ_ADD1] = START_CMD1; | |
| 183 FLASH[SEQ_ADD2] = START_CMD2; | |
| 184 FLASH[SEQ_ADD1] = STOP_CMD; | |
| 185 | |
| 186 // Wait at least 10ms | |
| 187 cyg_thread_delay(5); | |
| 188 | |
| 189 if (manuf_code != MAN_ATMEL) { | |
| 190 diag_printf ( "Error: Wrong Manufaturer: %02x\n",manuf_code ); | |
| 191 return (0); | |
| 192 } | |
| 193 | |
| 194 switch (device_code) { | |
| 195 case ATMEL_AT29C040A_ID: | |
| 196 diag_printf ("AT29C040A recognised\n"); | |
| 197 sector_size = ATMEL_SECTOR_SIZE; | |
| 198 max_no_of_sectors = ATMEL_MAX_SECTORS; | |
| 199 word_mode = FALSE; | |
| 200 break; | |
| 201 case ATMEL_AT29C1024_ID: | |
| 202 diag_printf ("AT29C1024 recognised\n"); | |
| 203 sector_size = ATMEL_SECTOR_SIZE; | |
| 204 max_no_of_sectors = ATMEL_MAX_SECTORS; | |
| 205 word_mode = TRUE; | |
| 206 break; | |
| 207 default : | |
| 208 diag_printf ( "Error: Unsupported device: %02x\n", device_code); | |
| 209 return (0); | |
| 210 } | |
| 211 return (1); | |
| 212 } | |
| 213 | |
| 214 void | |
| 215 write_sector(int num, char *buf) | |
| 216 { | |
| 217 int i, cnt; | |
| 218 volatile char *wrt = (volatile int *)&FLASH[num*sector_size]; | |
| 219 | |
| 220 // diag_printf("Writing to %08x\n", wrt); | |
| 221 // Enter Program Mode | |
| 222 FLASH[SEQ_ADD1] = START_CMD1; | |
| 223 FLASH[SEQ_ADD2] = START_CMD2; | |
| 224 FLASH[SEQ_ADD1] = PROG_CMD; | |
| 225 | |
| 226 // Note: write bytes as longs regardless of bus width | |
| 227 for (i = 0; i < sector_size; i++) { | |
| 228 wrt[i] = buf[i]; | |
| 229 } | |
| 230 | |
| 231 // Wait for sector to program | |
| 232 cnt = 0; | |
| 233 i = sector_size - 1; | |
| 234 while (wrt[i] != buf[i]) { | |
| 235 if (cnt++ > 0x01000000) break; | |
| 236 } | |
| 237 // diag_printf("Out - i: %d, wrt[i] = %08X.%08X, buf[i] = %08X, count = %x\n", i, &wrt[i], wrt[i], buf[i], cnt); | |
| 238 | |
| 239 // Verify | |
| 240 for (i = 0; i < sector_size; i++) { | |
| 241 for (cnt = 0; cnt < 10; cnt++) { | |
| 242 if (*wrt == *buf) break; | |
| 243 cyg_thread_delay(1); | |
| 244 } | |
| 245 if (cnt == 10) { | |
| 246 diag_printf("Can't program at 0x%08X: %02X not %02X\n", wrt, *wrt, *buf); | |
| 247 } | |
| 248 wrt++; buf++; | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 // S-record download code - viciously 'adapted' from "kernel/src/sload/sload.c" | |
| 253 | |
| 254 /*---------------------------------------------------------------------------*/ | |
| 255 /* | |
| 256 // | |
| 257 // An srecord looks like this: | |
| 258 // | |
| 259 // byte count-+ address | |
| 260 // start ---+ | | data +- checksum | |
| 261 // | | | | | |
| 262 // S01000006F6B692D746573742E73726563E4 | |
| 263 // S315000448600000000000000000FC00005900000000E9 | |
| 264 // S31A0004000023C1400037DE00F023604000377B009020825000348D | |
| 265 // S30B0004485A0000000000004E | |
| 266 // S70500040000F6 | |
| 267 // | |
| 268 // S<type><length><address><data><checksum> | |
| 269 // | |
| 270 // Where | |
| 271 // - length (2 characters) | |
| 272 // is the number of bytes following upto the checksum. Note that | |
| 273 // this is not the number of chars following, since it takes two | |
| 274 // chars to represent a byte. | |
| 275 // - type (2 characters) | |
| 276 // is one of: | |
| 277 // 0) header record | |
| 278 // 1) two byte address data record | |
| 279 // 2) three byte address data record | |
| 280 // 3) four byte address data record | |
| 281 // 5) record containing the number of S1, S2, or S3 records | |
| 282 // 7) four byte address termination record | |
| 283 // 8) three byte address termination record | |
| 284 // 9) two byte address termination record | |
| 285 // | |
| 286 // - address (4, 6, or 8 characters) | |
| 287 // is the start address of the data following, or in the case of | |
| 288 // a termination record, the start address of the image | |
| 289 // - data (0-2n characters) | |
| 290 // is the data. | |
| 291 // - checksum (2 characters) | |
| 292 // is the sum of all the raw byte data in the record, from the length | |
| 293 // upwards, modulo 256 and subtracted from 255. | |
| 294 // | |
| 295 // Useful S-records for testing purposes: | |
| 296 // Start record: | |
| 297 // S00B0000737461303030447563 | |
| 298 // This sets the default address to be 0x02005000: | |
| 299 // S31A020050002700801481C4E0B0A15000000100000091D02000018F | |
| 300 // S31A0200501500000001000000010000002700801881C4E2E4A150C1 | |
| 301 // S311020080A42407070A090B0A0781050000E1 | |
| 302 // Termination record: | |
| 303 // S70502005000A8 | |
| 304 // | |
| 305 */ | |
| 306 | |
| 307 #define S0 0 | |
| 308 #define S1 1 | |
| 309 #define S2 2 | |
| 310 #define S3 3 | |
| 311 #define S5 5 | |
| 312 #define S7 7 | |
| 313 #define S8 8 | |
| 314 #define S9 9 | |
| 315 | |
| 316 /*---------------------------------------------------------------------------*/ | |
| 317 | |
| 318 int hex2digit(char c) | |
| 319 { | |
| 320 if( c & 0x40 ) c += 9;; | |
| 321 return c &0x0f; | |
| 322 | |
| 323 // return ( c <= '9' ? c - '0' : | |
| 324 // c <= 'Z' ? c - 'A' + 10 : | |
| 325 // c - 'a' + 10); | |
| 326 } | |
| 327 | |
| 328 /*---------------------------------------------------------------------------*/ | |
| 329 | |
| 330 bool load_srecords(char (*readc)(), | |
| 331 CYG_ADDRESS *start, | |
| 332 int *size) | |
| 333 { | |
| 334 CYG_ADDRESS addr, load_addr; | |
| 335 int addrsize; | |
| 336 int length; | |
| 337 int i; | |
| 338 cyg_uint8 chksum, ochksum; | |
| 339 cyg_uint8 val; | |
| 340 cyg_uint8 *tdata; | |
| 341 char s; | |
| 342 char type; | |
| 343 char len0; | |
| 344 char len1; | |
| 345 bool first = true; | |
| 346 | |
| 347 | |
| 348 do { | |
| 349 // Skip whitespace characters until we find something that | |
| 350 // might be an 'S'. | |
| 351 do { | |
| 352 s = readc(); | |
| 353 } while( s == '\r' || s == '\n' || s == ' '); | |
| 354 | |
| 355 // Check that this is an S record | |
| 356 if( s != 'S' ) { | |
| 357 diag_printf("Invalid 'S' record\n"); | |
| 358 return false; | |
| 359 } | |
| 360 | |
| 361 // First 4 bytes are standard S + type + len | |
| 362 type = readc(); | |
| 363 len0 = readc(); | |
| 364 len1 = readc(); | |
| 365 | |
| 366 // decode the type | |
| 367 type = hex2digit(type); | |
| 368 | |
| 369 // determine address size | |
| 370 switch (type) { | |
| 371 case S0: // start records have no address | |
| 372 addrsize = 0; | |
| 373 break; | |
| 374 case S1: // two byte address | |
| 375 case S9: | |
| 376 addrsize = 4; | |
| 377 break; | |
| 378 case S2: // 3 byte address | |
| 379 case S8: | |
| 380 addrsize = 6; | |
| 381 break; | |
| 382 case S3: // 4 byte address | |
| 383 case S7: | |
| 384 addrsize = 8; | |
| 385 break; | |
| 386 } | |
| 387 | |
| 388 length = hex2digit (len0) << 4; | |
| 389 length |= hex2digit (len1); | |
| 390 chksum = length; | |
| 391 | |
| 392 // read the address | |
| 393 addr = 0; | |
| 394 for (i = 0; i < addrsize; i++) { | |
| 395 val = hex2digit(readc()); | |
| 396 addr = (addr << 4) | val; | |
| 397 } | |
| 398 | |
| 399 // calculate the checksum, which is done by the byte, not the digit | |
| 400 for (i = 0; i < addrsize*4; i += 8) { | |
| 401 chksum += ((addr >> i) & 0xff); | |
| 402 } | |
| 403 | |
| 404 // decide where to load this data | |
| 405 if (first && (type != S0)) { | |
| 406 load_addr = addr; | |
| 407 first = false; | |
| 408 } | |
| 409 | |
| 410 // read the data and put it directly into memory where it belongs | |
| 411 tdata = (cyg_uint8 *)((addr - load_addr) + flash_buffer); | |
| 412 if (type < S7) { | |
| 413 *size = (addr - load_addr); | |
| 414 } | |
| 415 val = 0; | |
| 416 for (i = 0; i < ((length - 1) * 2) - addrsize; i += 2 ) { | |
| 417 val = hex2digit (readc()) << 4; | |
| 418 val |= hex2digit (readc()); | |
| 419 chksum += val; | |
| 420 if( type != S0 ) *tdata++ = val; | |
| 421 if (type < S7) *size = *size + 1; | |
| 422 } | |
| 423 | |
| 424 // now get the old checksum | |
| 425 ochksum = hex2digit(readc()) << 4; | |
| 426 ochksum |= hex2digit(readc()); | |
| 427 chksum = ~chksum; | |
| 428 if (chksum != ochksum) { | |
| 429 diag_printf("Bad checksum - addr: %x\n", addr); | |
| 430 return false; | |
| 431 } | |
| 432 | |
| 433 } while( type < S7 ); | |
| 434 | |
| 435 *start = addr; | |
| 436 return true; | |
| 437 } |
