Bump version numbers for 3.13
[maemo-rb.git] / apps / plugins / iriver_flash.c
blob4e84cc4c0c1c82d8f8d41a8647d57e7152dd95b9
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 #ifndef IRIVER_H100_SERIES
31 #error this platform is not (yet) flashable
32 #endif
34 #if CONFIG_KEYPAD == IRIVER_H100_PAD
35 #define KEY1 BUTTON_OFF
36 #define KEY2 BUTTON_ON
37 #define KEY3 BUTTON_SELECT
38 #define KEYNAME1 "[Stop]"
39 #define KEYNAME2 "[On]"
40 #define KEYNAME3 "[Select]"
41 #endif
43 struct flash_info
45 uint8_t manufacturer;
46 uint8_t id;
47 int size;
48 char name[32];
51 #ifdef IRIVER_H100_SERIES
52 #define SEC_SIZE 4096
53 #define BOOTLOADER_ERASEGUARD (BOOTLOADER_ENTRYPOINT / SEC_SIZE)
54 enum sections {
55 SECT_RAMIMAGE = 1,
56 SECT_ROMIMAGE = 2,
59 static volatile uint16_t* FB = (uint16_t*)0x00000000; /* Flash base address */
60 #endif
62 /* read the manufacturer and device ID */
63 bool cfi_read_id(volatile uint16_t* pBase, uint8_t* pManufacturerID, uint8_t* pDeviceID)
65 uint8_t not_manu, not_id; /* read values before switching to ID mode */
66 uint8_t manu, id; /* read values when in ID mode */
68 pBase = (uint16_t*)((uint32_t)pBase & 0xFFF80000); /* down to 512k align */
70 /* read the normal content */
71 not_manu = pBase[0]; /* should be 'A' (0x41) and 'R' (0x52) */
72 not_id = pBase[1]; /* from the "ARCH" marker */
74 pBase[0x5555] = 0xAA; /* enter command mode */
75 pBase[0x2AAA] = 0x55;
76 pBase[0x5555] = 0x90; /* ID command */
77 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
79 manu = pBase[0];
80 id = pBase[1];
82 pBase[0] = 0xF0; /* reset flash (back to normal read mode) */
83 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
85 /* I assume success if the obtained values are different from
86 the normal flash content. This is not perfectly bulletproof, they
87 could theoretically be the same by chance, causing us to fail. */
88 if (not_manu != manu || not_id != id) /* a value has changed */
90 *pManufacturerID = manu; /* return the results */
91 *pDeviceID = id;
92 return true; /* success */
94 return false; /* fail */
98 /* erase the sector which contains the given address */
99 bool cfi_erase_sector(volatile uint16_t* pAddr)
101 unsigned timeout = 430000; /* the timeout loop should be no less than 25ms */
103 FB[0x5555] = 0xAA; /* enter command mode */
104 FB[0x2AAA] = 0x55;
105 FB[0x5555] = 0x80; /* erase command */
106 FB[0x5555] = 0xAA; /* enter command mode */
107 FB[0x2AAA] = 0x55;
108 *pAddr = 0x30; /* erase the sector */
110 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
111 /* Plus memory waitstates it will be much more, gives margin */
112 while (*pAddr != 0xFFFF && --timeout); /* poll for erased */
114 return (timeout != 0);
118 /* address must be in an erased location */
119 static inline bool cfi_program_word(volatile uint16_t* pAddr, uint16_t data)
121 unsigned timeout = 85; /* the timeout loop should be no less than 20us */
123 if (~*pAddr & data) /* just a safety feature, not really necessary */
124 return false; /* can't set any bit from 0 to 1 */
126 FB[0x5555] = 0xAA; /* enter command mode */
127 FB[0x2AAA] = 0x55;
128 FB[0x5555] = 0xA0; /* byte program command */
130 *pAddr = data;
132 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
133 /* Plus memory waitstates it will be much more, gives margin */
134 while (*pAddr != data && --timeout); /* poll for programmed */
136 return (timeout != 0);
140 /* this returns true if supported and fills the info struct */
141 bool cfi_get_flash_info(struct flash_info* pInfo)
143 rb->memset(pInfo, 0, sizeof(struct flash_info));
145 if (!cfi_read_id(FB, &pInfo->manufacturer, &pInfo->id))
146 return false;
148 if (pInfo->manufacturer == 0xBF) /* SST */
150 if (pInfo->id == 0xD6)
152 pInfo->size = 256* 1024; /* 256k */
153 rb->strcpy(pInfo->name, "SST39VF020");
154 return true;
156 else if (pInfo->id == 0xD7)
158 pInfo->size = 512* 1024; /* 512k */
159 rb->strcpy(pInfo->name, "SST39VF040");
160 return true;
162 else if (pInfo->id == 0x82)
164 pInfo->size = 2048* 1024; /* 2 MiB */
165 rb->strcpy(pInfo->name, "SST39VF160");
166 return true;
168 else
169 return false;
171 return false;
174 /***************** User Interface Functions *****************/
175 int wait_for_button(void)
177 int button;
181 button = rb->button_get(true);
182 } while (IS_SYSEVENT(button) || (button & BUTTON_REL));
184 return button;
187 /* helper for DoUserDialog() */
188 void ShowFlashInfo(struct flash_info* pInfo)
190 if (!pInfo->manufacturer)
192 rb->lcd_puts(0, 0, "Flash: M=?? D=??");
193 rb->lcd_puts(0, 1, "Impossible to program");
195 else
197 rb->lcd_putsf(0, 0, "Flash: M=%02x D=%02x",
198 pInfo->manufacturer, pInfo->id);
201 if (pInfo->size)
203 rb->lcd_puts(0, 1, pInfo->name);
204 rb->lcd_putsf(0, 2, "Size: %d KB", pInfo->size / 1024);
206 else
208 rb->lcd_puts(0, 1, "Unsupported chip");
213 rb->lcd_update();
216 bool show_info(void)
218 struct flash_info fi;
220 rb->lcd_clear_display();
221 cfi_get_flash_info(&fi);
222 ShowFlashInfo(&fi);
223 if (fi.size == 0) /* no valid chip */
225 rb->splash(HZ*3, "Sorry!");
226 return false; /* exit */
229 return true;
232 bool confirm(const char *msg)
234 bool ret;
236 rb->splashf(0, "%s ([PLAY] to CONFIRM)", msg);
238 ret = (wait_for_button() == BUTTON_ON);
239 show_info();
241 return ret;
244 int load_firmware_file(const char *filename, uint32_t *checksum)
246 int fd;
247 int len, rc;
248 int i;
249 uint32_t sum;
251 fd = rb->open(filename, O_RDONLY);
252 if (fd < 0)
253 return -1;
255 len = rb->filesize(fd);
257 if (audiobuf_size < len)
259 rb->splash(HZ*3, "Aborting: Out of memory!");
260 rb->close(fd);
261 return -2;
264 rb->read(fd, checksum, 4);
265 rb->lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET);
266 len -= FIRMWARE_OFFSET_FILE_DATA;
268 rc = rb->read(fd, audiobuf, len);
269 rb->close(fd);
270 if (rc != len)
272 rb->splash(HZ*3, "Aborting: Read failure");
273 return -3;
276 /* Verify the checksum */
277 sum = MODEL_NUMBER;
278 for (i = 0; i < len; i++)
279 sum += audiobuf[i];
281 if (sum != *checksum)
283 rb->splash(HZ*3, "Aborting: Checksums mismatch!");
284 return -4;
287 return len;
290 unsigned long valid_bootloaders[][2] = {
291 /* Size-8 CRC32 */
292 #ifdef IRIVER_H120 /* Iriver H120/H140 checksums */
293 { 63788, 0x08ff01a9 }, /* 7-pre3, improved failsafe functions */
294 { 48764, 0xc674323e }, /* 7-pre4. Fixed audio thump & remote bootup */
295 #endif
296 #ifdef IRIVER_H100
297 { 48760, 0x2efc3323 }, /* 7-pre4 */
298 #endif
299 { 0, 0 }
303 bool detect_valid_bootloader(const unsigned char *addr, int len)
305 int i;
306 unsigned long crc32;
308 /* Try to scan through all valid bootloaders. */
309 for (i = 0; valid_bootloaders[i][0]; i++)
311 if (len > 0 && len != (long)valid_bootloaders[i][0])
312 continue;
314 crc32 = rb->crc_32(addr, valid_bootloaders[i][0], 0xffffffff);
315 if (crc32 == valid_bootloaders[i][1])
316 return true;
319 return false;
322 static int get_section_address(int section)
324 if (section == SECT_RAMIMAGE)
325 return FLASH_RAMIMAGE_ENTRY;
326 else if (section == SECT_ROMIMAGE)
327 return FLASH_ROMIMAGE_ENTRY;
328 else
329 return -1;
332 int flash_rockbox(const char *filename, int section)
334 struct flash_header hdr;
335 int pos, i, len, rc;
336 unsigned long checksum, sum;
337 unsigned char *p8;
338 uint16_t *p16;
340 if (get_section_address(section) < 0)
341 return -1;
343 p8 = (char *)BOOTLOADER_ENTRYPOINT;
344 if (!detect_valid_bootloader(p8, 0))
346 rb->splash(HZ*3, "Incompatible bootloader");
347 return -1;
350 if (!rb->detect_original_firmware())
352 if (!confirm("Update Rockbox flash image?"))
353 return -2;
355 else
357 if (!confirm("Erase original firmware?"))
358 return -3;
361 len = load_firmware_file(filename, &checksum);
362 if (len <= 0)
363 return len * 10;
365 pos = get_section_address(section);
367 /* Check if image relocation seems to be sane. */
368 if (section == SECT_ROMIMAGE)
370 uint32_t *p32 = (uint32_t *)audiobuf;
372 if (pos+sizeof(struct flash_header) != *p32)
374 rb->splashf(HZ*10, "Incorrect relocation: 0x%08lx/0x%08lx",
375 *p32, pos+sizeof(struct flash_header));
376 return -1;
381 /* Erase the program flash. */
382 for (i = 0; i + pos < BOOTLOADER_ENTRYPOINT && i < len + 32; i += SEC_SIZE)
384 /* Additional safety check. */
385 if (i + pos < SEC_SIZE)
386 return -1;
388 rb->lcd_putsf(0, 3, "Erasing... %d%%", (i+SEC_SIZE)*100/len);
389 rb->lcd_update();
391 rc = cfi_erase_sector(FB + (i + pos)/2);
394 /* Write the magic and size. */
395 rb->memset(&hdr, 0, sizeof(struct flash_header));
396 hdr.magic = FLASH_MAGIC;
397 hdr.length = len;
398 // rb->strncpy(hdr.version, rb->rbversion , sizeof(hdr.version)-1);
399 p16 = (uint16_t *)&hdr;
401 rb->lcd_puts(0, 4, "Programming...");
402 rb->lcd_update();
404 pos = get_section_address(section)/2;
405 for (i = 0; i < (long)sizeof(struct flash_header)/2; i++)
407 cfi_program_word(FB + pos, p16[i]);
408 pos++;
411 p16 = (uint16_t *)audiobuf;
412 for (i = 0; i < len/2 && pos + i < (BOOTLOADER_ENTRYPOINT/2); i++)
414 if (i % SEC_SIZE == 0)
416 rb->lcd_putsf(0, 4, "Programming... %d%%", (i+1)*100/(len/2));
417 rb->lcd_update();
420 cfi_program_word(FB + pos + i, p16[i]);
423 /* Verify */
424 rb->lcd_puts(0, 5, "Verifying");
425 rb->lcd_update();
427 p8 = (char *)get_section_address(section);
428 p8 += sizeof(struct flash_header);
429 sum = MODEL_NUMBER;
430 for (i = 0; i < len; i++)
431 sum += p8[i];
433 if (sum != checksum)
435 rb->splash(HZ*3, "Verify failed!");
436 /* Erase the magic sector so bootloader does not try to load
437 * rockbox from flash and crash. */
438 if (section == SECT_RAMIMAGE)
439 cfi_erase_sector(FB + FLASH_RAMIMAGE_ENTRY/2);
440 else
441 cfi_erase_sector(FB + FLASH_ROMIMAGE_ENTRY/2);
442 return -5;
445 rb->splash(HZ*2, "Success");
447 return 0;
450 void show_fatal_error(void)
452 rb->splash(HZ*30, "Disable idle poweroff, connect AC power and DON'T TURN PLAYER OFF!!");
453 rb->splash(HZ*30, "Contact Rockbox developers as soon as possible!");
454 rb->splash(HZ*30, "Your device won't be bricked unless you turn off the power");
455 rb->splash(HZ*30, "Don't use the device before further instructions from Rockbox developers");
458 int flash_bootloader(const char *filename)
460 char *bootsector;
461 int pos, i, len, rc;
462 unsigned long checksum, sum;
463 unsigned char *p8;
464 uint16_t *p16;
466 bootsector = audiobuf;
467 audiobuf += SEC_SIZE;
468 audiobuf_size -= SEC_SIZE;
470 if (!confirm("Update bootloader?"))
471 return -2;
473 len = load_firmware_file(filename, &checksum);
474 if (len <= 0)
475 return len * 10;
477 if (len > 0xFFFF)
479 rb->splash(HZ*3, "Too big bootloader");
480 return -1;
483 /* Verify the crc32 checksum also. */
484 if (!detect_valid_bootloader(audiobuf, len))
486 rb->splash(HZ*3, "Incompatible/Untested bootloader");
487 return -1;
490 rb->lcd_puts(0, 3, "Flashing...");
491 rb->lcd_update();
493 /* Backup the bootloader sector first. */
494 p8 = (char *)FB;
495 rb->memcpy(bootsector, p8, SEC_SIZE);
497 /* Erase the boot sector and write a proper reset vector. */
498 cfi_erase_sector(FB);
499 p16 = (uint16_t *)audiobuf;
500 for (i = 0; i < 8/2; i++)
501 cfi_program_word(FB + i, p16[i]);
503 /* And restore original content for original FW to function. */
504 p16 = (uint16_t *)bootsector;
505 for (i = 8/2; i < SEC_SIZE/2; i++)
506 cfi_program_word(FB + i, p16[i]);
508 /* Erase the bootloader flash section. */
509 for (i = BOOTLOADER_ENTRYPOINT/SEC_SIZE; i < 0x200; i++)
510 rc = cfi_erase_sector(FB + (SEC_SIZE/2) * i);
512 pos = BOOTLOADER_ENTRYPOINT/2;
513 p16 = (uint16_t *)audiobuf;
514 for (i = 0; i < len/2; i++)
515 cfi_program_word(FB + pos + i, p16[i]);
517 /* Verify */
518 p8 = (char *)BOOTLOADER_ENTRYPOINT;
519 sum = MODEL_NUMBER;
520 for (i = 0; i < len; i++)
521 sum += p8[i];
523 if (sum != checksum)
525 rb->splash(HZ*3, "Verify failed!");
526 show_fatal_error();
527 return -5;
530 p8 = (char *)FB;
531 for (i = 0; i < 8; i++)
533 if (p8[i] != audiobuf[i])
535 rb->splash(HZ*3, "Bootvector corrupt!");
536 show_fatal_error();
537 return -6;
541 rb->splash(HZ*2, "Success");
543 return 0;
546 int flash_original_fw(int len)
548 unsigned char reset_vector[8];
549 int pos, i, rc;
550 unsigned char *p8;
551 uint16_t *p16;
553 rb->lcd_puts(0, 3, "Critical section...");
554 rb->lcd_update();
556 p8 = (char *)FB;
557 rb->memcpy(reset_vector, p8, sizeof reset_vector);
559 /* Erase the boot sector and write back the reset vector. */
560 cfi_erase_sector(FB);
561 p16 = (uint16_t *)reset_vector;
562 for (i = 0; i < (long)sizeof(reset_vector)/2; i++)
563 cfi_program_word(FB + i, p16[i]);
565 rb->lcd_puts(0, 4, "Flashing orig. FW");
566 rb->lcd_update();
568 /* Erase the program flash. */
569 for (i = 1; i < BOOTLOADER_ERASEGUARD && (i-1)*4096 < len; i++)
571 rc = cfi_erase_sector(FB + (SEC_SIZE/2) * i);
572 rb->lcd_putsf(0, 5, "Erase: 0x%03x (%d)", i, rc);
573 rb->lcd_update();
576 rb->lcd_puts(0, 6, "Programming");
577 rb->lcd_update();
579 pos = 0x00000008/2;
580 p16 = (uint16_t *)audiobuf;
581 for (i = 0; i < len/2 && pos + i < (BOOTLOADER_ENTRYPOINT/2); i++)
582 cfi_program_word(FB + pos + i, p16[i]);
584 rb->lcd_puts(0, 7, "Verifying");
585 rb->lcd_update();
587 /* Verify reset vectors. */
588 p8 = (char *)FB;
589 for (i = 0; i < 8; i++)
591 if (p8[i] != reset_vector[i])
593 rb->splash(HZ*3, "Bootvector corrupt!");
594 show_fatal_error();
595 break;
599 /* Verify */
600 p8 = (char *)0x00000008;
601 for (i = 0; i < len; i++)
603 if (p8[i] != audiobuf[i])
605 rb->splash(HZ*3, "Verify failed!");
606 rb->splashf(HZ*10, "at: 0x%08x", i);
607 return -5;
611 rb->splash(HZ*2, "Success");
613 return 0;
616 int load_original_bin(const char *filename)
618 unsigned long magic[2];
619 int len, rc;
620 int fd;
622 if (!confirm("Restore original firmware (bootloader will be kept)?"))
623 return -2;
625 fd = rb->open(filename, O_RDONLY);
626 if (fd < 0)
627 return -1;
629 len = rb->filesize(fd) - 0x228;
630 rb->lseek(fd, 0x220, SEEK_SET);
631 rb->read(fd, magic, 8);
632 if (magic[1] != 0x00000008 || len <= 0 || len > audiobuf_size)
634 rb->splash(HZ*2, "Not an original firmware file");
635 rb->close(fd);
636 return -1;
639 rc = rb->read(fd, audiobuf, len);
640 rb->close(fd);
642 if (rc != len)
644 rb->splash(HZ*2, "Read error");
645 return -2;
648 if (len % 2)
649 len++;
651 return flash_original_fw(len);
654 int load_romdump(const char *filename)
656 int len, rc;
657 int fd;
659 if (!confirm("Restore firmware section (bootloader will be kept)?"))
660 return -2;
662 fd = rb->open(filename, O_RDONLY);
663 if (fd < 0)
664 return -1;
666 len = rb->filesize(fd) - 8;
667 if (len <= 0)
668 return -1;
670 rb->lseek(fd, 8, SEEK_SET);
671 rc = rb->read(fd, audiobuf, len);
672 rb->close(fd);
674 if (rc != len)
676 rb->splash(HZ*2, "Read error");
677 return -2;
680 if (len % 2)
681 len++;
683 if (len > BOOTLOADER_ENTRYPOINT - 8)
684 len = BOOTLOADER_ENTRYPOINT - 8;
686 return flash_original_fw(len);
689 /* Kind of our main function, defines the application flow. */
690 void DoUserDialog(char* filename)
692 /* this can only work if Rockbox runs in DRAM, not flash ROM */
693 if ((uint16_t*)rb >= FB && (uint16_t*)rb < FB + 4096*1024) /* 4 MB max */
694 { /* we're running from flash */
695 rb->splash(HZ*3, "Not from ROM");
696 return; /* exit */
699 /* refuse to work if the power may fail meanwhile */
700 if (!rb->battery_level_safe())
702 rb->splash(HZ*3, "Battery too low!");
703 return; /* exit */
706 rb->lcd_setfont(FONT_SYSFIXED);
707 if (!show_info())
708 return ;
710 if (filename == NULL)
712 rb->splash(HZ*3, "Please use this plugin with \"Open with...\"");
713 return ;
716 audiobuf = rb->plugin_get_audio_buffer((size_t *)&audiobuf_size);
718 if (rb->strcasestr(filename, "/rockbox.iriver"))
719 flash_rockbox(filename, SECT_RAMIMAGE);
720 else if (rb->strcasestr(filename, "/rombox.iriver"))
721 flash_rockbox(filename, SECT_ROMIMAGE);
722 else if (rb->strcasestr(filename, "/bootloader.iriver"))
723 flash_bootloader(filename);
724 else if (rb->strcasestr(filename, "/ihp_120.bin"))
725 load_original_bin(filename);
726 else if (rb->strcasestr(filename, "/internal_rom_000000-1FFFFF.bin"))
727 load_romdump(filename);
728 else
729 rb->splash(HZ*3, "Unknown file type");
733 /***************** Plugin Entry Point *****************/
735 enum plugin_status plugin_start(const void* parameter)
737 int oldmode;
739 /* now go ahead and have fun! */
740 oldmode = rb->system_memory_guard(MEMGUARD_NONE); /*disable memory guard */
741 DoUserDialog((char*) parameter);
742 rb->system_memory_guard(oldmode); /* re-enable memory guard */
744 return PLUGIN_OK;