as3525: fix r26308
[kugel-rb.git] / apps / plugins / iriver_flash.c
blob3f5490e754269ef7da0f6cc24ee858f25631b2ac
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * !!! DON'T MESS WITH THIS CODE UNLESS YOU'RE ABSOLUTELY SURE WHAT YOU DO !!!
12 * Copyright (C) 2006 by Miika Pekkarinen
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
23 #include "plugin.h"
25 /* All CFI flash routines are copied and ported from firmware_flash.c */
27 unsigned char *audiobuf;
28 ssize_t audiobuf_size;
30 #ifdef IRIVER_H100_SERIES
31 #define PLATFORM_ID ID_IRIVER_H100
32 #else
33 #undef PLATFORM_ID /* this platform is not (yet) flashable */
34 #endif
36 #ifdef PLATFORM_ID
38 PLUGIN_HEADER
40 #if CONFIG_KEYPAD == IRIVER_H100_PAD
41 #define KEY1 BUTTON_OFF
42 #define KEY2 BUTTON_ON
43 #define KEY3 BUTTON_SELECT
44 #define KEYNAME1 "[Stop]"
45 #define KEYNAME2 "[On]"
46 #define KEYNAME3 "[Select]"
47 #endif
49 struct flash_info
51 uint8_t manufacturer;
52 uint8_t id;
53 int size;
54 char name[32];
57 #ifdef IRIVER_H100_SERIES
58 #define SEC_SIZE 4096
59 #define BOOTLOADER_ERASEGUARD (BOOTLOADER_ENTRYPOINT / SEC_SIZE)
60 enum sections {
61 SECT_RAMIMAGE = 1,
62 SECT_ROMIMAGE = 2,
65 static volatile uint16_t* FB = (uint16_t*)0x00000000; /* Flash base address */
66 #endif
68 /* read the manufacturer and device ID */
69 bool cfi_read_id(volatile uint16_t* pBase, uint8_t* pManufacturerID, uint8_t* pDeviceID)
71 uint8_t not_manu, not_id; /* read values before switching to ID mode */
72 uint8_t manu, id; /* read values when in ID mode */
74 pBase = (uint16_t*)((uint32_t)pBase & 0xFFF80000); /* down to 512k align */
76 /* read the normal content */
77 not_manu = pBase[0]; /* should be 'A' (0x41) and 'R' (0x52) */
78 not_id = pBase[1]; /* from the "ARCH" marker */
80 pBase[0x5555] = 0xAA; /* enter command mode */
81 pBase[0x2AAA] = 0x55;
82 pBase[0x5555] = 0x90; /* ID command */
83 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
85 manu = pBase[0];
86 id = pBase[1];
88 pBase[0] = 0xF0; /* reset flash (back to normal read mode) */
89 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
91 /* I assume success if the obtained values are different from
92 the normal flash content. This is not perfectly bulletproof, they
93 could theoretically be the same by chance, causing us to fail. */
94 if (not_manu != manu || not_id != id) /* a value has changed */
96 *pManufacturerID = manu; /* return the results */
97 *pDeviceID = id;
98 return true; /* success */
100 return false; /* fail */
104 /* erase the sector which contains the given address */
105 bool cfi_erase_sector(volatile uint16_t* pAddr)
107 unsigned timeout = 430000; /* the timeout loop should be no less than 25ms */
109 FB[0x5555] = 0xAA; /* enter command mode */
110 FB[0x2AAA] = 0x55;
111 FB[0x5555] = 0x80; /* erase command */
112 FB[0x5555] = 0xAA; /* enter command mode */
113 FB[0x2AAA] = 0x55;
114 *pAddr = 0x30; /* erase the sector */
116 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
117 /* Plus memory waitstates it will be much more, gives margin */
118 while (*pAddr != 0xFFFF && --timeout); /* poll for erased */
120 return (timeout != 0);
124 /* address must be in an erased location */
125 inline bool cfi_program_word(volatile uint16_t* pAddr, uint16_t data)
127 unsigned timeout = 85; /* the timeout loop should be no less than 20us */
129 if (~*pAddr & data) /* just a safety feature, not really necessary */
130 return false; /* can't set any bit from 0 to 1 */
132 FB[0x5555] = 0xAA; /* enter command mode */
133 FB[0x2AAA] = 0x55;
134 FB[0x5555] = 0xA0; /* byte program command */
136 *pAddr = data;
138 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
139 /* Plus memory waitstates it will be much more, gives margin */
140 while (*pAddr != data && --timeout); /* poll for programmed */
142 return (timeout != 0);
146 /* this returns true if supported and fills the info struct */
147 bool cfi_get_flash_info(struct flash_info* pInfo)
149 rb->memset(pInfo, 0, sizeof(struct flash_info));
151 if (!cfi_read_id(FB, &pInfo->manufacturer, &pInfo->id))
152 return false;
154 if (pInfo->manufacturer == 0xBF) /* SST */
156 if (pInfo->id == 0xD6)
158 pInfo->size = 256* 1024; /* 256k */
159 rb->strcpy(pInfo->name, "SST39VF020");
160 return true;
162 else if (pInfo->id == 0xD7)
164 pInfo->size = 512* 1024; /* 512k */
165 rb->strcpy(pInfo->name, "SST39VF040");
166 return true;
168 else if (pInfo->id == 0x82)
170 pInfo->size = 2048* 1024; /* 2 MiB */
171 rb->strcpy(pInfo->name, "SST39VF160");
172 return true;
174 else
175 return false;
177 return false;
180 /***************** User Interface Functions *****************/
181 int wait_for_button(void)
183 int button;
187 button = rb->button_get(true);
188 } while (IS_SYSEVENT(button) || (button & BUTTON_REL));
190 return button;
193 /* helper for DoUserDialog() */
194 void ShowFlashInfo(struct flash_info* pInfo)
196 char buf[32];
198 if (!pInfo->manufacturer)
200 rb->lcd_puts(0, 0, "Flash: M=?? D=??");
201 rb->lcd_puts(0, 1, "Impossible to program");
203 else
205 rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
206 pInfo->manufacturer, pInfo->id);
207 rb->lcd_puts(0, 0, buf);
210 if (pInfo->size)
212 rb->lcd_puts(0, 1, pInfo->name);
213 rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
214 rb->lcd_puts(0, 2, buf);
216 else
218 rb->lcd_puts(0, 1, "Unsupported chip");
223 rb->lcd_update();
226 bool show_info(void)
228 struct flash_info fi;
230 rb->lcd_clear_display();
231 cfi_get_flash_info(&fi);
232 ShowFlashInfo(&fi);
233 if (fi.size == 0) /* no valid chip */
235 rb->splash(HZ*3, "Sorry!");
236 return false; /* exit */
239 return true;
242 bool confirm(const char *msg)
244 char buf[128];
245 bool ret;
247 rb->snprintf(buf, sizeof buf, "%s ([PLAY] to CONFIRM)", msg);
248 rb->splash(0, buf);
250 ret = (wait_for_button() == BUTTON_ON);
251 show_info();
253 return ret;
256 int load_firmware_file(const char *filename, uint32_t *checksum)
258 int fd;
259 int len, rc;
260 int i;
261 uint32_t sum;
263 fd = rb->open(filename, O_RDONLY);
264 if (fd < 0)
265 return -1;
267 len = rb->filesize(fd);
269 if (audiobuf_size < len)
271 rb->splash(HZ*3, "Aborting: Out of memory!");
272 rb->close(fd);
273 return -2;
276 rb->read(fd, checksum, 4);
277 rb->lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET);
278 len -= FIRMWARE_OFFSET_FILE_DATA;
280 rc = rb->read(fd, audiobuf, len);
281 rb->close(fd);
282 if (rc != len)
284 rb->splash(HZ*3, "Aborting: Read failure");
285 return -3;
288 /* Verify the checksum */
289 sum = MODEL_NUMBER;
290 for (i = 0; i < len; i++)
291 sum += audiobuf[i];
293 if (sum != *checksum)
295 rb->splash(HZ*3, "Aborting: Checksums mismatch!");
296 return -4;
299 return len;
302 unsigned long valid_bootloaders[][2] = {
303 /* Size-8 CRC32 */
304 #ifdef IRIVER_H120 /* Iriver H120/H140 checksums */
305 { 63788, 0x08ff01a9 }, /* 7-pre3, improved failsafe functions */
306 { 48764, 0xc674323e }, /* 7-pre4. Fixed audio thump & remote bootup */
307 #endif
308 #ifdef IRIVER_H100
309 { 48760, 0x2efc3323 }, /* 7-pre4 */
310 #endif
311 { 0, 0 }
315 bool detect_valid_bootloader(const unsigned char *addr, int len)
317 int i;
318 unsigned long crc32;
320 /* Try to scan through all valid bootloaders. */
321 for (i = 0; valid_bootloaders[i][0]; i++)
323 if (len > 0 && len != (long)valid_bootloaders[i][0])
324 continue;
326 crc32 = rb->crc_32(addr, valid_bootloaders[i][0], 0xffffffff);
327 if (crc32 == valid_bootloaders[i][1])
328 return true;
331 return false;
334 static int get_section_address(int section)
336 if (section == SECT_RAMIMAGE)
337 return FLASH_RAMIMAGE_ENTRY;
338 else if (section == SECT_ROMIMAGE)
339 return FLASH_ROMIMAGE_ENTRY;
340 else
341 return -1;
344 int flash_rockbox(const char *filename, int section)
346 struct flash_header hdr;
347 char buf[64];
348 int pos, i, len, rc;
349 unsigned long checksum, sum;
350 unsigned char *p8;
351 uint16_t *p16;
353 if (get_section_address(section) < 0)
354 return -1;
356 p8 = (char *)BOOTLOADER_ENTRYPOINT;
357 if (!detect_valid_bootloader(p8, 0))
359 rb->splash(HZ*3, "Incompatible bootloader");
360 return -1;
363 if (!rb->detect_original_firmware())
365 if (!confirm("Update Rockbox flash image?"))
366 return -2;
368 else
370 if (!confirm("Erase original firmware?"))
371 return -3;
374 len = load_firmware_file(filename, &checksum);
375 if (len <= 0)
376 return len * 10;
378 pos = get_section_address(section);
380 /* Check if image relocation seems to be sane. */
381 if (section == SECT_ROMIMAGE)
383 uint32_t *p32 = (uint32_t *)audiobuf;
385 if (pos+sizeof(struct flash_header) != *p32)
387 rb->snprintf(buf, sizeof(buf), "Incorrect relocation: 0x%08lx/0x%08lx",
388 *p32, pos+sizeof(struct flash_header));
389 rb->splash(HZ*10, buf);
390 return -1;
395 /* Erase the program flash. */
396 for (i = 0; i + pos < BOOTLOADER_ENTRYPOINT && i < len + 32; i += SEC_SIZE)
398 /* Additional safety check. */
399 if (i + pos < SEC_SIZE)
400 return -1;
402 rb->snprintf(buf, sizeof(buf), "Erasing... %d%%",
403 (i+SEC_SIZE)*100/len);
404 rb->lcd_puts(0, 3, buf);
405 rb->lcd_update();
407 rc = cfi_erase_sector(FB + (i + pos)/2);
410 /* Write the magic and size. */
411 rb->memset(&hdr, 0, sizeof(struct flash_header));
412 hdr.magic = FLASH_MAGIC;
413 hdr.length = len;
414 // rb->strncpy(hdr.version, APPSVERSION, sizeof(hdr.version)-1);
415 p16 = (uint16_t *)&hdr;
417 rb->snprintf(buf, sizeof(buf), "Programming...");
418 rb->lcd_puts(0, 4, buf);
419 rb->lcd_update();
421 pos = get_section_address(section)/2;
422 for (i = 0; i < (long)sizeof(struct flash_header)/2; i++)
424 cfi_program_word(FB + pos, p16[i]);
425 pos++;
428 p16 = (uint16_t *)audiobuf;
429 for (i = 0; i < len/2 && pos + i < (BOOTLOADER_ENTRYPOINT/2); i++)
431 if (i % SEC_SIZE == 0)
433 rb->snprintf(buf, sizeof(buf), "Programming... %d%%",
434 (i+1)*100/(len/2));
435 rb->lcd_puts(0, 4, buf);
436 rb->lcd_update();
439 cfi_program_word(FB + pos + i, p16[i]);
442 /* Verify */
443 rb->snprintf(buf, sizeof(buf), "Verifying");
444 rb->lcd_puts(0, 5, buf);
445 rb->lcd_update();
447 p8 = (char *)get_section_address(section);
448 p8 += sizeof(struct flash_header);
449 sum = MODEL_NUMBER;
450 for (i = 0; i < len; i++)
451 sum += p8[i];
453 if (sum != checksum)
455 rb->splash(HZ*3, "Verify failed!");
456 /* Erase the magic sector so bootloader does not try to load
457 * rockbox from flash and crash. */
458 if (section == SECT_RAMIMAGE)
459 cfi_erase_sector(FB + FLASH_RAMIMAGE_ENTRY/2);
460 else
461 cfi_erase_sector(FB + FLASH_ROMIMAGE_ENTRY/2);
462 return -5;
465 rb->splash(HZ*2, "Success");
467 return 0;
470 void show_fatal_error(void)
472 rb->splash(HZ*30, "Disable idle poweroff, connect AC power and DON'T TURN PLAYER OFF!!");
473 rb->splash(HZ*30, "Contact Rockbox developers as soon as possible!");
474 rb->splash(HZ*30, "Your device won't be bricked unless you turn off the power");
475 rb->splash(HZ*30, "Don't use the device before further instructions from Rockbox developers");
478 int flash_bootloader(const char *filename)
480 char *bootsector;
481 int pos, i, len, rc;
482 unsigned long checksum, sum;
483 unsigned char *p8;
484 uint16_t *p16;
486 bootsector = audiobuf;
487 audiobuf += SEC_SIZE;
488 audiobuf_size -= SEC_SIZE;
490 if (!confirm("Update bootloader?"))
491 return -2;
493 len = load_firmware_file(filename, &checksum);
494 if (len <= 0)
495 return len * 10;
497 if (len > 0xFFFF)
499 rb->splash(HZ*3, "Too big bootloader");
500 return -1;
503 /* Verify the crc32 checksum also. */
504 if (!detect_valid_bootloader(audiobuf, len))
506 rb->splash(HZ*3, "Incompatible/Untested bootloader");
507 return -1;
510 rb->lcd_puts(0, 3, "Flashing...");
511 rb->lcd_update();
513 /* Backup the bootloader sector first. */
514 p8 = (char *)FB;
515 rb->memcpy(bootsector, p8, SEC_SIZE);
517 /* Erase the boot sector and write a proper reset vector. */
518 cfi_erase_sector(FB);
519 p16 = (uint16_t *)audiobuf;
520 for (i = 0; i < 8/2; i++)
521 cfi_program_word(FB + i, p16[i]);
523 /* And restore original content for original FW to function. */
524 p16 = (uint16_t *)bootsector;
525 for (i = 8/2; i < SEC_SIZE/2; i++)
526 cfi_program_word(FB + i, p16[i]);
528 /* Erase the bootloader flash section. */
529 for (i = BOOTLOADER_ENTRYPOINT/SEC_SIZE; i < 0x200; i++)
530 rc = cfi_erase_sector(FB + (SEC_SIZE/2) * i);
532 pos = BOOTLOADER_ENTRYPOINT/2;
533 p16 = (uint16_t *)audiobuf;
534 for (i = 0; i < len/2; i++)
535 cfi_program_word(FB + pos + i, p16[i]);
537 /* Verify */
538 p8 = (char *)BOOTLOADER_ENTRYPOINT;
539 sum = MODEL_NUMBER;
540 for (i = 0; i < len; i++)
541 sum += p8[i];
543 if (sum != checksum)
545 rb->splash(HZ*3, "Verify failed!");
546 show_fatal_error();
547 return -5;
550 p8 = (char *)FB;
551 for (i = 0; i < 8; i++)
553 if (p8[i] != audiobuf[i])
555 rb->splash(HZ*3, "Bootvector corrupt!");
556 show_fatal_error();
557 return -6;
561 rb->splash(HZ*2, "Success");
563 return 0;
566 int flash_original_fw(int len)
568 unsigned char reset_vector[8];
569 char buf[32];
570 int pos, i, rc;
571 unsigned char *p8;
572 uint16_t *p16;
574 (void)buf;
576 rb->lcd_puts(0, 3, "Critical section...");
577 rb->lcd_update();
579 p8 = (char *)FB;
580 rb->memcpy(reset_vector, p8, sizeof reset_vector);
582 /* Erase the boot sector and write back the reset vector. */
583 cfi_erase_sector(FB);
584 p16 = (uint16_t *)reset_vector;
585 for (i = 0; i < (long)sizeof(reset_vector)/2; i++)
586 cfi_program_word(FB + i, p16[i]);
588 rb->lcd_puts(0, 4, "Flashing orig. FW");
589 rb->lcd_update();
591 /* Erase the program flash. */
592 for (i = 1; i < BOOTLOADER_ERASEGUARD && (i-1)*4096 < len; i++)
594 rc = cfi_erase_sector(FB + (SEC_SIZE/2) * i);
595 rb->snprintf(buf, sizeof(buf), "Erase: 0x%03x (%d)", i, rc);
596 rb->lcd_puts(0, 5, buf);
597 rb->lcd_update();
600 rb->snprintf(buf, sizeof(buf), "Programming");
601 rb->lcd_puts(0, 6, buf);
602 rb->lcd_update();
604 pos = 0x00000008/2;
605 p16 = (uint16_t *)audiobuf;
606 for (i = 0; i < len/2 && pos + i < (BOOTLOADER_ENTRYPOINT/2); i++)
607 cfi_program_word(FB + pos + i, p16[i]);
609 rb->snprintf(buf, sizeof(buf), "Verifying");
610 rb->lcd_puts(0, 7, buf);
611 rb->lcd_update();
613 /* Verify reset vectors. */
614 p8 = (char *)FB;
615 for (i = 0; i < 8; i++)
617 if (p8[i] != reset_vector[i])
619 rb->splash(HZ*3, "Bootvector corrupt!");
620 show_fatal_error();
621 break;
625 /* Verify */
626 p8 = (char *)0x00000008;
627 for (i = 0; i < len; i++)
629 if (p8[i] != audiobuf[i])
631 rb->splash(HZ*3, "Verify failed!");
632 rb->snprintf(buf, sizeof buf, "at: 0x%08x", i);
633 rb->splash(HZ*10, buf);
634 return -5;
638 rb->splash(HZ*2, "Success");
640 return 0;
643 int load_original_bin(const char *filename)
645 unsigned long magic[2];
646 int len, rc;
647 int fd;
649 if (!confirm("Restore original firmware (bootloader will be kept)?"))
650 return -2;
652 fd = rb->open(filename, O_RDONLY);
653 if (fd < 0)
654 return -1;
656 len = rb->filesize(fd) - 0x228;
657 rb->lseek(fd, 0x220, SEEK_SET);
658 rb->read(fd, magic, 8);
659 if (magic[1] != 0x00000008 || len <= 0 || len > audiobuf_size)
661 rb->splash(HZ*2, "Not an original firmware file");
662 rb->close(fd);
663 return -1;
666 rc = rb->read(fd, audiobuf, len);
667 rb->close(fd);
669 if (rc != len)
671 rb->splash(HZ*2, "Read error");
672 return -2;
675 if (len % 2)
676 len++;
678 return flash_original_fw(len);
681 int load_romdump(const char *filename)
683 int len, rc;
684 int fd;
686 if (!confirm("Restore firmware section (bootloader will be kept)?"))
687 return -2;
689 fd = rb->open(filename, O_RDONLY);
690 if (fd < 0)
691 return -1;
693 len = rb->filesize(fd) - 8;
694 if (len <= 0)
695 return -1;
697 rb->lseek(fd, 8, SEEK_SET);
698 rc = rb->read(fd, audiobuf, len);
699 rb->close(fd);
701 if (rc != len)
703 rb->splash(HZ*2, "Read error");
704 return -2;
707 if (len % 2)
708 len++;
710 if (len > BOOTLOADER_ENTRYPOINT - 8)
711 len = BOOTLOADER_ENTRYPOINT - 8;
713 return flash_original_fw(len);
716 /* Kind of our main function, defines the application flow. */
717 void DoUserDialog(char* filename)
719 /* this can only work if Rockbox runs in DRAM, not flash ROM */
720 if ((uint16_t*)rb >= FB && (uint16_t*)rb < FB + 4096*1024) /* 4 MB max */
721 { /* we're running from flash */
722 rb->splash(HZ*3, "Not from ROM");
723 return; /* exit */
726 /* refuse to work if the power may fail meanwhile */
727 if (!rb->battery_level_safe())
729 rb->splash(HZ*3, "Battery too low!");
730 return; /* exit */
733 rb->lcd_setfont(FONT_SYSFIXED);
734 if (!show_info())
735 return ;
737 if (filename == NULL)
739 rb->splash(HZ*3, "Please use this plugin with \"Open with...\"");
740 return ;
743 audiobuf = rb->plugin_get_audio_buffer((size_t *)&audiobuf_size);
745 if (rb->strcasestr(filename, "/rockbox.iriver"))
746 flash_rockbox(filename, SECT_RAMIMAGE);
747 else if (rb->strcasestr(filename, "/rombox.iriver"))
748 flash_rockbox(filename, SECT_ROMIMAGE);
749 else if (rb->strcasestr(filename, "/bootloader.iriver"))
750 flash_bootloader(filename);
751 else if (rb->strcasestr(filename, "/ihp_120.bin"))
752 load_original_bin(filename);
753 else if (rb->strcasestr(filename, "/internal_rom_000000-1FFFFF.bin"))
754 load_romdump(filename);
755 else
756 rb->splash(HZ*3, "Unknown file type");
760 /***************** Plugin Entry Point *****************/
762 enum plugin_status plugin_start(const void* parameter)
764 int oldmode;
766 /* now go ahead and have fun! */
767 oldmode = rb->system_memory_guard(MEMGUARD_NONE); /*disable memory guard */
768 DoUserDialog((char*) parameter);
769 rb->system_memory_guard(oldmode); /* re-enable memory guard */
771 return PLUGIN_OK;
774 #endif /* ifdef PLATFORM_ID */