mirror of
				https://github.com/Rockbox/rockbox.git
				synced 2025-10-26 23:36:37 -04:00 
			
		
		
		
	FiiO M3K: New bootloader
SPL and UCL-compressed bootloader are now packed into one output, bootloader.m3k, eliminating the separate SPL build phase. The Rockbox bootloader now has a recovery menu, accessible by holding VOL+ when booting, that lets you back up, restore, and update the bootloader from the device. Change-Id: I642c6e5fb83587a013ab2fbfd1adab439561ced2
This commit is contained in:
		
							parent
							
								
									cc22df198d
								
							
						
					
					
						commit
						3f26fcf340
					
				
					 22 changed files with 799 additions and 499 deletions
				
			
		|  | @ -89,6 +89,6 @@ show_logo.c | ||||||
| #elif defined(SANSA_CONNECT) | #elif defined(SANSA_CONNECT) | ||||||
| sansaconnect.c | sansaconnect.c | ||||||
| show_logo.c | show_logo.c | ||||||
| #elif defined(FIIO_M3K) && !defined(BOOTLOADER_SPL) | #elif defined(FIIO_M3K) | ||||||
| fiiom3k.c | fiiom3k.c | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ | ||||||
|  ****************************************************************************/ |  ****************************************************************************/ | ||||||
| 
 | 
 | ||||||
| #include "system.h" | #include "system.h" | ||||||
|  | #include "core_alloc.h" | ||||||
| #include "kernel/kernel-internal.h" | #include "kernel/kernel-internal.h" | ||||||
| #include "i2c.h" | #include "i2c.h" | ||||||
| #include "power.h" | #include "power.h" | ||||||
|  | @ -35,6 +36,9 @@ | ||||||
| #include "rb-loader.h" | #include "rb-loader.h" | ||||||
| #include "loader_strerror.h" | #include "loader_strerror.h" | ||||||
| #include "version.h" | #include "version.h" | ||||||
|  | #include "installer-fiiom3k.h" | ||||||
|  | #include "spl-x1000.h" | ||||||
|  | #include "x1000/cpm.h" | ||||||
| 
 | 
 | ||||||
| /* Load address where the binary needs to be placed */ | /* Load address where the binary needs to be placed */ | ||||||
| extern unsigned char loadaddress[]; | extern unsigned char loadaddress[]; | ||||||
|  | @ -59,6 +63,7 @@ void exec(void* dst, const void* src, int bytes) | ||||||
| 
 | 
 | ||||||
| static bool lcd_inited = false; | static bool lcd_inited = false; | ||||||
| static bool usb_inited = false; | static bool usb_inited = false; | ||||||
|  | static bool disk_inited = false; | ||||||
| 
 | 
 | ||||||
| static void init_lcd(void) | static void init_lcd(void) | ||||||
| { | { | ||||||
|  | @ -79,6 +84,12 @@ static void init_lcd(void) | ||||||
|     lcd_inited = true; |     lcd_inited = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void put_version(void) | ||||||
|  | { | ||||||
|  |     lcd_putsxy((LCD_WIDTH - (SYSFONT_WIDTH * strlen(rbversion))) / 2, | ||||||
|  |                (LCD_HEIGHT - SYSFONT_HEIGHT), rbversion); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void do_splash2(int delay, const char* msg, const char* msg2) | static void do_splash2(int delay, const char* msg, const char* msg2) | ||||||
| { | { | ||||||
|     init_lcd(); |     init_lcd(); | ||||||
|  | @ -90,8 +101,7 @@ static void do_splash2(int delay, const char* msg, const char* msg2) | ||||||
|                    (LCD_HEIGHT + 2*SYSFONT_HEIGHT) / 2, msg2); |                    (LCD_HEIGHT + 2*SYSFONT_HEIGHT) / 2, msg2); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     lcd_putsxy((LCD_WIDTH - (SYSFONT_WIDTH * strlen(rbversion))) / 2, |     put_version(); | ||||||
|                (LCD_HEIGHT - SYSFONT_HEIGHT), rbversion); |  | ||||||
|     lcd_update(); |     lcd_update(); | ||||||
|     sleep(delay); |     sleep(delay); | ||||||
| } | } | ||||||
|  | @ -109,20 +119,232 @@ static void do_usb(void) | ||||||
|         usb_inited = true; |         usb_inited = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     do_splash(0, "Waiting for USB"); |     do_splash2(0, "Waiting for USB", "Press POWER to go back"); | ||||||
|  | 
 | ||||||
|  |     int btn; | ||||||
|  |     while(1) { | ||||||
|  |         btn = button_get(true); | ||||||
|  |         if(btn == SYS_USB_CONNECTED) | ||||||
|  |            break; | ||||||
|  |         else if(btn == BUTTON_POWER) | ||||||
|  |             return; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     while(button_get(true) != SYS_USB_CONNECTED); |  | ||||||
|     do_splash(0, "USB mode"); |     do_splash(0, "USB mode"); | ||||||
| 
 |  | ||||||
|     usb_acknowledge(SYS_USB_CONNECTED_ACK); |     usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||||||
|     while(button_get(true) != SYS_USB_DISCONNECTED); |     while(button_get(true) != SYS_USB_DISCONNECTED); | ||||||
| 
 | 
 | ||||||
|     do_splash(3*HZ, "USB disconnected"); |     do_splash(3*HZ, "USB disconnected"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int init_disk(void) | ||||||
|  | { | ||||||
|  |     if(disk_inited) | ||||||
|  |         return 0; | ||||||
|  | 
 | ||||||
|  |     while(!storage_present(0)) { | ||||||
|  |         do_splash2(0, "Insert SD card", "Press POWER for recovery"); | ||||||
|  |         int btn = button_get_w_tmo(HZ); | ||||||
|  |         if(btn == BUTTON_POWER) | ||||||
|  |             return 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(disk_mount_all() <= 0) { | ||||||
|  |         do_splash(5*HZ, "Cannot mount filesystem"); | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     disk_inited = true; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void do_boot(void) | ||||||
|  | { | ||||||
|  |     if(init_disk() != 0) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     int loadsize = load_firmware(loadbuffer, BOOTFILE, MAX_LOAD_SIZE); | ||||||
|  |     if(loadsize <= 0) { | ||||||
|  |         do_splash2(5*HZ, "Error loading Rockbox", | ||||||
|  |                    loader_strerror(loadsize)); | ||||||
|  |         do_usb(); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(lcd_inited) | ||||||
|  |         backlight_hw_off(); | ||||||
|  | 
 | ||||||
|  |     disable_irq(); | ||||||
|  |     exec(loadaddress, loadbuffer, loadsize); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define INSTALL 0 | ||||||
|  | #define BACKUP  1 | ||||||
|  | #define RESTORE 2 | ||||||
|  | 
 | ||||||
|  | static void do_install(int which) | ||||||
|  | { | ||||||
|  |     int rc = init_disk(); | ||||||
|  |     if(rc != 0) { | ||||||
|  |         do_splash2(5*HZ, "Install aborted", "No SD card present"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const char* msg; | ||||||
|  |     if(rc == INSTALL) | ||||||
|  |         msg = "Installing"; | ||||||
|  |     else if(rc == BACKUP) | ||||||
|  |         msg = "Backing up"; | ||||||
|  |     else | ||||||
|  |         msg = "Restoring backup"; | ||||||
|  | 
 | ||||||
|  |     do_splash(0, msg); | ||||||
|  | 
 | ||||||
|  |     if(which == INSTALL) | ||||||
|  |         rc = install_boot("/bootloader.m3k"); | ||||||
|  |     else if(which == BACKUP) | ||||||
|  |         rc = backup_boot("/fiiom3k-boot.bin"); | ||||||
|  |     else | ||||||
|  |         rc = restore_boot("/fiiom3k-boot.bin"); | ||||||
|  | 
 | ||||||
|  |     char buf[32]; | ||||||
|  |     snprintf(buf, sizeof(buf), "Failed! Error: %d", rc); | ||||||
|  |     const char* msg1 = rc == 0 ? "Success" : buf; | ||||||
|  |     const char* msg2 = "Press POWER to continue"; | ||||||
|  |     do_splash2(0, msg1, msg2); | ||||||
|  | 
 | ||||||
|  |     button_clear_queue(); | ||||||
|  |     while(button_get(true) != BUTTON_POWER); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void recovery_menu(void) | ||||||
|  | { | ||||||
|  |     static const char* items[] = { | ||||||
|  |         "--- Rockbox recovery menu ---", | ||||||
|  |         "[System]", | ||||||
|  |         "   Start Rockbox", | ||||||
|  |         "   USB mode", | ||||||
|  |         "   Shutdown", | ||||||
|  |         "   Reboot", | ||||||
|  |         "[Bootloader]", | ||||||
|  |         "   Install or update", | ||||||
|  |         "   Backup", | ||||||
|  |         "   Restore", | ||||||
|  |         "", | ||||||
|  |         "", | ||||||
|  |         "", | ||||||
|  |         "", | ||||||
|  |         "", | ||||||
|  |         "VOL+/VOL-         move cursor", | ||||||
|  |         "PLAY              select item", | ||||||
|  |         "POWER               power off", | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     static const int nitems = sizeof(items) / sizeof(char*); | ||||||
|  | 
 | ||||||
|  |     init_lcd(); | ||||||
|  | 
 | ||||||
|  |     int selection = 2; | ||||||
|  |     do { | ||||||
|  |         /* Draw menu */ | ||||||
|  |         lcd_clear_display(); | ||||||
|  | 
 | ||||||
|  |         for(int i = 0; i < nitems; ++i) | ||||||
|  |             lcd_puts(0, i, items[i]); | ||||||
|  | 
 | ||||||
|  |         if(items[selection][0] == ' ') | ||||||
|  |             lcd_puts(0, selection, "=>"); | ||||||
|  | 
 | ||||||
|  |         put_version(); | ||||||
|  |         lcd_update(); | ||||||
|  | 
 | ||||||
|  |         /* Clear queue to avoid accidental input */ | ||||||
|  |         button_clear_queue(); | ||||||
|  | 
 | ||||||
|  |         /* Get the button */ | ||||||
|  |         int btn = button_get(true); | ||||||
|  | 
 | ||||||
|  |         /* Process user input */ | ||||||
|  |         if(btn == BUTTON_VOL_UP) { | ||||||
|  |             for(int i = selection-1; i >= 0; --i) { | ||||||
|  |                 if(items[i][0] == ' ') { | ||||||
|  |                     selection = i; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             continue; | ||||||
|  |         } else if(btn == BUTTON_VOL_DOWN) { | ||||||
|  |             for(int i = selection+1; i < nitems; ++i) { | ||||||
|  |                 if(items[i][0] == ' ') { | ||||||
|  |                     selection = i; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             continue; | ||||||
|  |         } else if(btn == BUTTON_POWER) { | ||||||
|  |             selection = 4; /* Shutdown */ | ||||||
|  |         } else if(btn != BUTTON_PLAY) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /* User pressed PLAY so decide what action to take */ | ||||||
|  |         switch(selection) { | ||||||
|  |         case 2: /* Start rockbox */ | ||||||
|  |             do_boot(); | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case 3: /* USB mode */ | ||||||
|  |             do_usb(); | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case 4: /* Shutdown */ | ||||||
|  |             do_splash(HZ, "Shutting down"); | ||||||
|  |             power_off(); | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case 5: /* Reboot */ | ||||||
|  |             do_splash(HZ, "Rebooting"); | ||||||
|  |             system_reboot(); | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case 7: /* Install bootloader */ | ||||||
|  |             do_install(INSTALL); | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case 8: /* Backup bootloader */ | ||||||
|  |             do_install(BACKUP); | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case 9: /* Restore bootloader */ | ||||||
|  |             do_install(RESTORE); | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } while(1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void main(void) | void main(void) | ||||||
| { | { | ||||||
|  |     bool recovery_mode = false; | ||||||
|  | 
 | ||||||
|  |     /* This hack is needed because when USB booting, we cannot initialize
 | ||||||
|  |      * clocks in the SPL -- it may break the mask ROM's USB code. So if the | ||||||
|  |      * SPL has not already initialized the clocks, we need to do that now. | ||||||
|  |      * | ||||||
|  |      * Also use this as a sign that we should enter the recovery menu since | ||||||
|  |      * this is probably the expected result if the user is USB booting... | ||||||
|  |      */ | ||||||
|  |     if(jz_readf(CPM_MPCR, ENABLE)) { | ||||||
|  |         spl_handle_pre_boot(0); | ||||||
|  |         recovery_mode = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     system_init(); |     system_init(); | ||||||
|  |     core_allocator_init(); | ||||||
|     kernel_init(); |     kernel_init(); | ||||||
|     i2c_init(); |     i2c_init(); | ||||||
|     power_init(); |     power_init(); | ||||||
|  | @ -136,32 +358,12 @@ void main(void) | ||||||
| 
 | 
 | ||||||
|     filesystem_init(); |     filesystem_init(); | ||||||
| 
 | 
 | ||||||
|     int loadsize = 0; |     if(button_read_device() & BUTTON_VOL_UP) | ||||||
|     do { |         recovery_mode = true; | ||||||
|         if(!storage_present(0)) { |  | ||||||
|             do_splash(HZ, "Insert SD card"); |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if(disk_mount_all() <= 0) { |     if(!recovery_mode) | ||||||
|             do_splash(5*HZ, "Cannot mount filesystem"); |         do_boot(); | ||||||
|             do_usb(); |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         loadsize = load_firmware(loadbuffer, BOOTFILE, MAX_LOAD_SIZE); |     /* If boot fails or user holds Vol+, go to recovery menu */ | ||||||
|         if(loadsize <= 0) { |     recovery_menu(); | ||||||
|             do_splash2(5*HZ, "Error loading Rockbox", |  | ||||||
|                        loader_strerror(loadsize)); |  | ||||||
|             do_usb(); |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
|     } while(loadsize <= 0); |  | ||||||
| 
 |  | ||||||
|     if(lcd_inited) |  | ||||||
|         backlight_hw_off(); |  | ||||||
| 
 |  | ||||||
|     disable_irq(); |  | ||||||
| 
 |  | ||||||
|     exec(loadaddress, loadbuffer, loadsize); |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1664,9 +1664,9 @@ target/mips/ingenic_x1000/msc-x1000.c | ||||||
| #if (CONFIG_STORAGE & STORAGE_SD) | #if (CONFIG_STORAGE & STORAGE_SD) | ||||||
| target/mips/ingenic_x1000/sd-x1000.c | target/mips/ingenic_x1000/sd-x1000.c | ||||||
| #endif | #endif | ||||||
| #ifdef BOOTLOADER_SPL | target/mips/ingenic_x1000/spl-start.S | ||||||
| target/mips/ingenic_x1000/spl-x1000.c | target/mips/ingenic_x1000/spl-x1000.c | ||||||
| #endif | common/ucl_decompress.c | ||||||
| #endif /* CONFIG_CPU == X1000 */ | #endif /* CONFIG_CPU == X1000 */ | ||||||
| 
 | 
 | ||||||
| #if defined(ONDA_VX747) || defined(ONDA_VX747P) || defined(ONDA_VX777) | #if defined(ONDA_VX747) || defined(ONDA_VX747P) || defined(ONDA_VX777) | ||||||
|  | @ -1696,11 +1696,11 @@ target/mips/ingenic_jz47xx/xduoo_x3/sadc-xduoo_x3.c | ||||||
| target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c | target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c | ||||||
| target/mips/ingenic_x1000/fiiom3k/backlight-fiiom3k.c | target/mips/ingenic_x1000/fiiom3k/backlight-fiiom3k.c | ||||||
| target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c | target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c | ||||||
| target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c |  | ||||||
| target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c | target/mips/ingenic_x1000/fiiom3k/lcd-fiiom3k.c | ||||||
| target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c | target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c | ||||||
| #ifdef BOOTLOADER_SPL |  | ||||||
| target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c | target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c | ||||||
|  | #ifdef BOOTLOADER | ||||||
|  | target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c | ||||||
| #endif | #endif | ||||||
| #endif /* FIIO_M3K */ | #endif /* FIIO_M3K */ | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,31 +0,0 @@ | ||||||
| /***************************************************************************
 |  | ||||||
|  *             __________               __   ___. |  | ||||||
|  *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___ |  | ||||||
|  *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 |  | ||||||
|  *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  < |  | ||||||
|  *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \ |  | ||||||
|  *                     \/            \/     \/    \/            \/ |  | ||||||
|  * $Id$ |  | ||||||
|  * |  | ||||||
|  * Copyright (C) 2021 Aidan MacDonald |  | ||||||
|  * |  | ||||||
|  * This program is free software; you can redistribute it and/or |  | ||||||
|  * modify it under the terms of the GNU General Public License |  | ||||||
|  * as published by the Free Software Foundation; either version 2 |  | ||||||
|  * of the License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |  | ||||||
|  * KIND, either express or implied. |  | ||||||
|  * |  | ||||||
|  ****************************************************************************/ |  | ||||||
| 
 |  | ||||||
| #ifndef _INSTALLER_H_ |  | ||||||
| #define _INSTALLER_H_ |  | ||||||
| 
 |  | ||||||
| /* Provisional interface for installing/dumping a bootloader */ |  | ||||||
| 
 |  | ||||||
| extern int install_bootloader(const char* path); |  | ||||||
| extern int dump_bootloader(const char* path); |  | ||||||
| extern const char* installer_strerror(int rc); |  | ||||||
| 
 |  | ||||||
| #endif /* _INSTALLER_H_ */ |  | ||||||
|  | @ -1,5 +1 @@ | ||||||
| #ifdef BOOTLOADER_SPL | #include "app.lds" | ||||||
| # include "spl.lds" |  | ||||||
| #else |  | ||||||
| # include "app.lds" |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  | @ -34,33 +34,6 @@ | ||||||
|     .section .init.text |     .section .init.text | ||||||
| 
 | 
 | ||||||
| _start: | _start: | ||||||
|     /* Clear data watchpoint */ |  | ||||||
|     mtc0    zero, C0_WATCHLO |  | ||||||
|     mtc0    zero, C0_WATCHHI |  | ||||||
| 
 |  | ||||||
|     /* Set BEV, ERL, mask interrupts */ |  | ||||||
|     li      v0, 0x40fc04 |  | ||||||
|     mtc0    v0, C0_Status |  | ||||||
| 
 |  | ||||||
|     /* Set Cause_IV to 1 (use special interrupt vector) */ |  | ||||||
|     li      v0, M_CauseIV |  | ||||||
|     mtc0    v0, C0_Cause |  | ||||||
| 
 |  | ||||||
|     /* Set CPU_MODE and BUS_MODE to 1 in CPM_OPCR (Ingenic does this) */ |  | ||||||
|     lui     v0, 0xb000 |  | ||||||
|     lw      v1, 0x24(v0) |  | ||||||
|     ori     v1, v1, 0x22 |  | ||||||
|     sw      v1, 0x24(v0) |  | ||||||
| 
 |  | ||||||
|     /* Enable kseg0 cacheability */ |  | ||||||
|     li      v0, 3 |  | ||||||
|     mtc0    v0, C0_Config |  | ||||||
|     nop |  | ||||||
| 
 |  | ||||||
|     /* According to ingenic: "enable idx-store-data cache insn" */ |  | ||||||
|     li      v0, 0x20000000 |  | ||||||
|     mtc0    v0, C0_ErrCtl |  | ||||||
| 
 |  | ||||||
|     /* Cache init */ |     /* Cache init */ | ||||||
|     li      v0, 0x80000000 |     li      v0, 0x80000000 | ||||||
|     ori     v1, v0, 0x4000 |     ori     v1, v0, 0x4000 | ||||||
|  | @ -80,7 +53,6 @@ _cache_loop: | ||||||
|     mtc0    v0, C0_Config, 7 |     mtc0    v0, C0_Config, 7 | ||||||
|     nop |     nop | ||||||
| 
 | 
 | ||||||
| #ifndef BOOTLOADER_SPL |  | ||||||
|     /* Copy IRAM from BSS to low memory. */ |     /* Copy IRAM from BSS to low memory. */ | ||||||
|     la      t0, _iramcopy |     la      t0, _iramcopy | ||||||
|     la      t1, _iramstart |     la      t1, _iramstart | ||||||
|  | @ -91,7 +63,6 @@ _iram_loop: | ||||||
|     addiu   t0, 4 |     addiu   t0, 4 | ||||||
|     bne     t1, t2, _iram_loop |     bne     t1, t2, _iram_loop | ||||||
|     sw      t3, -4(t1) |     sw      t3, -4(t1) | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
|     /* Clear the BSS segment (needed to zero-initialize C static values) */ |     /* Clear the BSS segment (needed to zero-initialize C static values) */ | ||||||
|     la      t0, _bssbegin |     la      t0, _bssbegin | ||||||
|  | @ -103,7 +74,6 @@ _bss_loop: | ||||||
|     sw      zero, -4(t0) |     sw      zero, -4(t0) | ||||||
| _bss_done: | _bss_done: | ||||||
| 
 | 
 | ||||||
| #ifndef BOOTLOADER_SPL |  | ||||||
|     /* Set stack pointer and clear the stack */ |     /* Set stack pointer and clear the stack */ | ||||||
|     la      sp, stackend |     la      sp, stackend | ||||||
|     la      t0, stackbegin |     la      t0, stackbegin | ||||||
|  | @ -120,13 +90,11 @@ _irqstack_loop: | ||||||
|     addiu   t0, 4 |     addiu   t0, 4 | ||||||
|     bne     t0, k0, _irqstack_loop |     bne     t0, k0, _irqstack_loop | ||||||
|     sw      t1, -4(t0) |     sw      t1, -4(t0) | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
|     /* Jump to C code */ |     /* Jump to C code */ | ||||||
|     j       main |     j       main | ||||||
|     nop |     nop | ||||||
| 
 | 
 | ||||||
| #ifndef BOOTLOADER_SPL |  | ||||||
|     /* Exception entry points */ |     /* Exception entry points */ | ||||||
|     .section .vectors.1, "ax", %progbits |     .section .vectors.1, "ax", %progbits | ||||||
|     j       tlb_refill_handler |     j       tlb_refill_handler | ||||||
|  | @ -260,6 +228,5 @@ _exception_return: | ||||||
|     lw      sp, 0x80(sp) |     lw      sp, 0x80(sp) | ||||||
|     eret |     eret | ||||||
|     nop |     nop | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
|     .set pop
 |     .set pop
 | ||||||
|  |  | ||||||
							
								
								
									
										30
									
								
								firmware/target/mips/ingenic_x1000/fiiom3k/boot.make
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								firmware/target/mips/ingenic_x1000/fiiom3k/boot.make
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | ||||||
|  | #             __________               __   ___. | ||||||
|  | #   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___ | ||||||
|  | #   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  / | ||||||
|  | #   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  < | ||||||
|  | #   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \ | ||||||
|  | #                     \/            \/     \/    \/            \/ | ||||||
|  | # $Id$ | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | include $(ROOTDIR)/lib/microtar/microtar.make | ||||||
|  | 
 | ||||||
|  | .SECONDEXPANSION: | ||||||
|  | 
 | ||||||
|  | $(BUILDDIR)/spl.m3k: $(BUILDDIR)/spl.bin | ||||||
|  | 	$(call PRINTS,MKSPL $(@F))$(TOOLSDIR)/mkspl-x1000 -type=nand -ppb=2 -bpp=2 $< $@ | ||||||
|  | 
 | ||||||
|  | $(BUILDDIR)/bootloader.ucl: $(BUILDDIR)/bootloader.bin | ||||||
|  | 	$(call PRINTS,UCLPACK $(@F))$(TOOLSDIR)/uclpack --nrv2e -9 $< $@ >/dev/null | ||||||
|  | 
 | ||||||
|  | .PHONY: $(BUILDDIR)/bootloader-info.txt | ||||||
|  | $(BUILDDIR)/bootloader-info.txt: | ||||||
|  | 	$(call PRINTS,GEN $(@F))echo $(SVNVERSION) > $@ | ||||||
|  | 
 | ||||||
|  | $(BUILDDIR)/$(BINARY): $(BUILDDIR)/spl.m3k \ | ||||||
|  | 					   $(BUILDDIR)/bootloader.ucl \ | ||||||
|  | 					   $(BUILDDIR)/bootloader-info.txt | ||||||
|  | 	$(call PRINTS,TAR $(@F))tar -C $(BUILDDIR) \ | ||||||
|  | 		--numeric-owner --no-acls --no-xattrs --no-selinux \ | ||||||
|  | 		--mode=0644 --owner=0 --group=0 \ | ||||||
|  | 		-cf $@ $(call full_path_subst,$(BUILDDIR)/%,%,$^) | ||||||
|  | @ -19,192 +19,265 @@ | ||||||
|  * |  * | ||||||
|  ****************************************************************************/ |  ****************************************************************************/ | ||||||
| 
 | 
 | ||||||
| #include "installer.h" | #include "installer-fiiom3k.h" | ||||||
| #include "nand-x1000.h" | #include "nand-x1000.h" | ||||||
| #include "system.h" | #include "system.h" | ||||||
| #include "core_alloc.h" | #include "core_alloc.h" | ||||||
| #include "file.h" | #include "file.h" | ||||||
|  | #include "microtar.h" | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <stdio.h> | ||||||
| 
 | 
 | ||||||
| #define INSTALL_SUCCESS             0 | #define IMAGE_SIZE  (128 * 1024) | ||||||
| #define ERR_FLASH_OPEN_FAILED       (-1) | #define TAR_SIZE    (256 * 1024) | ||||||
| #define ERR_FLASH_ENABLE_WP_FAILED  (-2) |  | ||||||
| #define ERR_FLASH_DISABLE_WP_FAILED (-3) |  | ||||||
| #define ERR_FLASH_ERASE_FAILED      (-4) |  | ||||||
| #define ERR_FLASH_WRITE_FAILED      (-5) |  | ||||||
| #define ERR_FLASH_READ_FAILED       (-6) |  | ||||||
| #define ERR_OUT_OF_MEMORY           (-7) |  | ||||||
| #define ERR_CANNOT_READ_FILE        (-8) |  | ||||||
| #define ERR_CANNOT_WRITE_FILE       (-9) |  | ||||||
| #define ERR_WRONG_SIZE              (-10) |  | ||||||
| 
 | 
 | ||||||
| #define BOOT_IMAGE_SIZE (128 * 1024) | static int flash_prepare(void) | ||||||
| 
 |  | ||||||
| static int install_from_buffer(const void* buf) |  | ||||||
| { | { | ||||||
|     int status = INSTALL_SUCCESS; |  | ||||||
|     int mf_id, dev_id; |     int mf_id, dev_id; | ||||||
|  |     int rc; | ||||||
| 
 | 
 | ||||||
|     if(nand_open()) |     rc = nand_open(); | ||||||
|         return ERR_FLASH_OPEN_FAILED; |     if(rc < 0) | ||||||
|     if(nand_identify(&mf_id, &dev_id)) { |         return INSTALL_ERR_FLASH(NAND_OPEN, rc); | ||||||
|         status = ERR_FLASH_OPEN_FAILED; | 
 | ||||||
|         goto _exit; |     rc = nand_identify(&mf_id, &dev_id); | ||||||
|  |     if(rc < 0) { | ||||||
|  |         nand_close(); | ||||||
|  |         return INSTALL_ERR_FLASH(NAND_IDENTIFY, rc); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(nand_enable_writes(true)) { |     return INSTALL_SUCCESS; | ||||||
|         status = ERR_FLASH_DISABLE_WP_FAILED; |  | ||||||
|         goto _exit; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(nand_erase(0, BOOT_IMAGE_SIZE)) { |  | ||||||
|         status = ERR_FLASH_ERASE_FAILED; |  | ||||||
|         goto _exit; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(nand_write(0, BOOT_IMAGE_SIZE, (const uint8_t*)buf)) { |  | ||||||
|         status = ERR_FLASH_WRITE_FAILED; |  | ||||||
|         goto _exit; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(nand_enable_writes(false)) { |  | ||||||
|         status = ERR_FLASH_ENABLE_WP_FAILED; |  | ||||||
|         goto _exit; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|   _exit: |  | ||||||
|     nand_close(); |  | ||||||
|     return status; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int dump_to_buffer(void* buf) | static void flash_finish(void) | ||||||
| { | { | ||||||
|     int status = INSTALL_SUCCESS; |     /* Ensure writes are always disabled when we finish.
 | ||||||
|     int mf_id, dev_id; |      * Errors are safe to ignore here, there's nothing we could do anyway. */ | ||||||
| 
 |     nand_enable_writes(false); | ||||||
|     if(nand_open()) |  | ||||||
|         return ERR_FLASH_OPEN_FAILED; |  | ||||||
|     if(nand_identify(&mf_id, &dev_id)) { |  | ||||||
|         status = ERR_FLASH_OPEN_FAILED; |  | ||||||
|         goto _exit; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(nand_read(0, BOOT_IMAGE_SIZE, (uint8_t*)buf)) { |  | ||||||
|         status = ERR_FLASH_READ_FAILED; |  | ||||||
|         goto _exit; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|   _exit: |  | ||||||
|     nand_close(); |     nand_close(); | ||||||
|     return status; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int install_bootloader(const char* path) | static int flash_img_read(uint8_t* buffer) | ||||||
| { | { | ||||||
|     /* Allocate memory to hold image */ |     int rc = flash_prepare(); | ||||||
|     size_t bufsize = BOOT_IMAGE_SIZE + CACHEALIGN_SIZE - 1; |     if(rc < 0) | ||||||
|     int handle = core_alloc("boot_image", bufsize); |         goto error; | ||||||
|     if(handle < 0) |  | ||||||
|         return ERR_OUT_OF_MEMORY; |  | ||||||
| 
 | 
 | ||||||
|     int status = INSTALL_SUCCESS; |     rc = nand_read(0, IMAGE_SIZE, buffer); | ||||||
|     void* buffer = core_get_data(handle); |     if(rc < 0) { | ||||||
|  |         rc = INSTALL_ERR_FLASH(NAND_READ, rc); | ||||||
|  |         goto error; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |   error: | ||||||
|  |     flash_finish(); | ||||||
|  |     return rc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int flash_img_write(const uint8_t* buffer) | ||||||
|  | { | ||||||
|  |     int rc = flash_prepare(); | ||||||
|  |     if(rc < 0) | ||||||
|  |         goto error; | ||||||
|  | 
 | ||||||
|  |     rc = nand_enable_writes(true); | ||||||
|  |     if(rc < 0) { | ||||||
|  |         rc = INSTALL_ERR_FLASH(NAND_ENABLE_WRITES, rc); | ||||||
|  |         goto error; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     rc = nand_erase(0, IMAGE_SIZE); | ||||||
|  |     if(rc < 0) { | ||||||
|  |         rc = INSTALL_ERR_FLASH(NAND_ERASE, rc); | ||||||
|  |         goto error; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     rc = nand_write(0, IMAGE_SIZE, buffer); | ||||||
|  |     if(rc < 0) { | ||||||
|  |         rc = INSTALL_ERR_FLASH(NAND_WRITE, rc); | ||||||
|  |         goto error; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |   error: | ||||||
|  |     flash_finish(); | ||||||
|  |     return rc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int patch_img(mtar_t* tar, uint8_t* buffer, const char* filename, | ||||||
|  |                      size_t patch_offset, size_t patch_size) | ||||||
|  | { | ||||||
|  |     /* Seek to file */ | ||||||
|  |     mtar_header_t h; | ||||||
|  |     int rc = mtar_find(tar, filename, &h); | ||||||
|  |     if(rc != MTAR_ESUCCESS) { | ||||||
|  |         rc = INSTALL_ERR_MTAR(TAR_FIND, rc); | ||||||
|  |         return rc; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* We need a normal file */ | ||||||
|  |     if(h.type != 0 && h.type != MTAR_TREG) | ||||||
|  |         return INSTALL_ERR_BAD_FORMAT; | ||||||
|  | 
 | ||||||
|  |     /* Check size does not exceed patch area */ | ||||||
|  |     if(h.size > patch_size) | ||||||
|  |         return INSTALL_ERR_BAD_FORMAT; | ||||||
|  | 
 | ||||||
|  |     /* Read data directly into patch area, fill unused bytes with 0xff */ | ||||||
|  |     memset(&buffer[patch_offset], 0xff, patch_size); | ||||||
|  |     rc = mtar_read_data(tar, &buffer[patch_offset], h.size); | ||||||
|  |     if(rc != MTAR_ESUCCESS) { | ||||||
|  |         rc = INSTALL_ERR_MTAR(TAR_READ, rc); | ||||||
|  |         return rc; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return INSTALL_SUCCESS; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int install_boot(const char* srcfile) | ||||||
|  | { | ||||||
|  |     int rc; | ||||||
|  |     mtar_t* tar = NULL; | ||||||
|  |     int handle = -1; | ||||||
|  | 
 | ||||||
|  |     /* Allocate enough memory for image and tar state */ | ||||||
|  |     size_t bufsize = IMAGE_SIZE + sizeof(mtar_t) + 2*CACHEALIGN_SIZE; | ||||||
|  |     handle = core_alloc("boot_image", bufsize); | ||||||
|  |     if(handle < 0) { | ||||||
|  |         rc = INSTALL_ERR_OUT_OF_MEMORY; | ||||||
|  |         goto error; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     uint8_t* buffer = core_get_data(handle); | ||||||
|  | 
 | ||||||
|  |     /* Tar state alloc */ | ||||||
|  |     CACHEALIGN_BUFFER(buffer, bufsize); | ||||||
|  |     tar = (mtar_t*)buffer; | ||||||
|  |     memset(tar, 0, sizeof(tar)); | ||||||
|  | 
 | ||||||
|  |     /* Image buffer alloc */ | ||||||
|  |     buffer += sizeof(mtar_t); | ||||||
|     CACHEALIGN_BUFFER(buffer, bufsize); |     CACHEALIGN_BUFFER(buffer, bufsize); | ||||||
| 
 | 
 | ||||||
|     /* Open the boot image */ |     /* Read the flash -- we need an existing image to patch */ | ||||||
|     int fd = open(path, O_RDONLY); |     rc = flash_img_read(buffer); | ||||||
|     if(fd < 0) { |     if(rc < 0) | ||||||
|         status = ERR_CANNOT_READ_FILE; |         goto error; | ||||||
|         goto _exit; | 
 | ||||||
|  |     /* Open the tarball */ | ||||||
|  |     rc = mtar_open(tar, srcfile, "r"); | ||||||
|  |     if(rc != MTAR_ESUCCESS) { | ||||||
|  |         rc = INSTALL_ERR_MTAR(TAR_OPEN, rc); | ||||||
|  |         goto error; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Check file size */ |     /* Extract the needed files & patch 'em in */ | ||||||
|     off_t fsize = filesize(fd); |     rc = patch_img(tar, buffer, "spl.m3k", 0, 12 * 1024); | ||||||
|     if(fsize != BOOT_IMAGE_SIZE) { |     if(rc < 0) | ||||||
|         status = ERR_WRONG_SIZE; |         goto error; | ||||||
|         goto _exit; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /* Read the file into the buffer */ |     rc = patch_img(tar, buffer, "bootloader.ucl", 0x6800, 102 * 1024); | ||||||
|     ssize_t cnt = read(fd, buffer, BOOT_IMAGE_SIZE); |     if(rc < 0) | ||||||
|     if(cnt != BOOT_IMAGE_SIZE) { |         goto error; | ||||||
|         status = ERR_CANNOT_READ_FILE; |  | ||||||
|         goto _exit; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /* Perform the installation */ |     /* Flash the new image */ | ||||||
|     status = install_from_buffer(buffer); |     rc = flash_img_write(buffer); | ||||||
|  |     if(rc < 0) | ||||||
|  |         goto error; | ||||||
| 
 | 
 | ||||||
|   _exit: |     rc = INSTALL_SUCCESS; | ||||||
|     if(fd >= 0) | 
 | ||||||
|         close(fd); |   error: | ||||||
|     core_free(handle); |     if(tar && tar->close) | ||||||
|     return status; |         mtar_close(tar); | ||||||
|  |     if(handle >= 0) | ||||||
|  |         core_free(handle); | ||||||
|  |     return rc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Dump the current bootloader to a file */ | int backup_boot(const char* destfile) | ||||||
| int dump_bootloader(const char* path) |  | ||||||
| { | { | ||||||
|     /* Allocate memory to hold image */ |     int rc; | ||||||
|     size_t bufsize = BOOT_IMAGE_SIZE + CACHEALIGN_SIZE - 1; |     int handle = -1; | ||||||
|     int handle = core_alloc("boot_image", bufsize); |  | ||||||
|     if(handle < 0) |  | ||||||
|         return -1; |  | ||||||
| 
 |  | ||||||
|     /* Read data from flash */ |  | ||||||
|     int fd = -1; |     int fd = -1; | ||||||
|     void* buffer = core_get_data(handle); |     size_t bufsize = IMAGE_SIZE + CACHEALIGN_SIZE - 1; | ||||||
|  |     handle = core_alloc("boot_image", bufsize); | ||||||
|  |     if(handle < 0) { | ||||||
|  |         rc = INSTALL_ERR_OUT_OF_MEMORY; | ||||||
|  |         goto error; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     uint8_t* buffer = core_get_data(handle); | ||||||
|     CACHEALIGN_BUFFER(buffer, bufsize); |     CACHEALIGN_BUFFER(buffer, bufsize); | ||||||
|     int status = dump_to_buffer(buffer); |  | ||||||
|     if(status) |  | ||||||
|         goto _exit; |  | ||||||
| 
 | 
 | ||||||
|     /* Open file */ |     rc = flash_img_read(buffer); | ||||||
|     fd = open(path, O_CREAT|O_TRUNC|O_WRONLY); |     if(rc < 0) | ||||||
|  |         goto error; | ||||||
|  | 
 | ||||||
|  |     fd = open(destfile, O_CREAT|O_TRUNC|O_WRONLY); | ||||||
|     if(fd < 0) { |     if(fd < 0) { | ||||||
|         status = ERR_CANNOT_WRITE_FILE; |         rc = INSTALL_ERR_FILE_IO; | ||||||
|         goto _exit; |         goto error; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Write data to file */ |     ssize_t cnt = write(fd, buffer, IMAGE_SIZE); | ||||||
|     ssize_t cnt = write(fd, buffer, BOOT_IMAGE_SIZE); |     if(cnt != IMAGE_SIZE) { | ||||||
|     if(cnt != BOOT_IMAGE_SIZE) { |         rc = INSTALL_ERR_FILE_IO; | ||||||
|         status = ERR_CANNOT_WRITE_FILE; |         goto error; | ||||||
|         goto _exit; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|   _exit: |   error: | ||||||
|     if(fd >= 0) |     if(fd >= 0) | ||||||
|         close(fd); |         close(fd); | ||||||
|     core_free(handle); |     if(handle >= 0) | ||||||
|     return status; |         core_free(handle); | ||||||
|  |     return rc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const char* installer_strerror(int rc) | int restore_boot(const char* srcfile) | ||||||
| { | { | ||||||
|     switch(rc) { |     int rc; | ||||||
|     case INSTALL_SUCCESS: |     int handle = -1; | ||||||
|         return "Success"; |     int fd = -1; | ||||||
|     case ERR_FLASH_OPEN_FAILED: |     size_t bufsize = IMAGE_SIZE + CACHEALIGN_SIZE - 1; | ||||||
|         return "Can't open flash device"; |     handle = core_alloc("boot_image", bufsize); | ||||||
|     case ERR_FLASH_ENABLE_WP_FAILED: |     if(handle < 0) { | ||||||
|         return "Couldn't re-enable write protect"; |         rc = INSTALL_ERR_OUT_OF_MEMORY; | ||||||
|     case ERR_FLASH_DISABLE_WP_FAILED: |         goto error; | ||||||
|         return "Can't disable write protect"; |  | ||||||
|     case ERR_FLASH_ERASE_FAILED: |  | ||||||
|         return "Flash erase failed"; |  | ||||||
|     case ERR_FLASH_WRITE_FAILED: |  | ||||||
|         return "Flash write error"; |  | ||||||
|     case ERR_FLASH_READ_FAILED: |  | ||||||
|         return "Flash read error"; |  | ||||||
|     case ERR_OUT_OF_MEMORY: |  | ||||||
|         return "Out of memory"; |  | ||||||
|     case ERR_CANNOT_READ_FILE: |  | ||||||
|         return "Error reading file"; |  | ||||||
|     case ERR_CANNOT_WRITE_FILE: |  | ||||||
|         return "Error writing file"; |  | ||||||
|     case ERR_WRONG_SIZE: |  | ||||||
|         return "Wrong file size"; |  | ||||||
|     default: |  | ||||||
|         return "Unknown error"; |  | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     uint8_t* buffer = core_get_data(handle); | ||||||
|  |     CACHEALIGN_BUFFER(buffer, bufsize); | ||||||
|  | 
 | ||||||
|  |     fd = open(srcfile, O_RDONLY); | ||||||
|  |     if(fd < 0) { | ||||||
|  |         rc = INSTALL_ERR_FILE_NOT_FOUND; | ||||||
|  |         goto error; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     off_t fsize = filesize(fd); | ||||||
|  |     if(fsize != IMAGE_SIZE) { | ||||||
|  |         rc = INSTALL_ERR_BAD_FORMAT; | ||||||
|  |         goto error; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ssize_t cnt = read(fd, buffer, IMAGE_SIZE); | ||||||
|  |     if(cnt != IMAGE_SIZE) { | ||||||
|  |         rc = INSTALL_ERR_FILE_IO; | ||||||
|  |         goto error; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     close(fd); | ||||||
|  |     fd = -1; | ||||||
|  | 
 | ||||||
|  |     rc = flash_img_write(buffer); | ||||||
|  |     if(rc < 0) | ||||||
|  |         goto error; | ||||||
|  | 
 | ||||||
|  |   error: | ||||||
|  |     if(fd >= 0) | ||||||
|  |         close(fd); | ||||||
|  |     if(handle >= 0) | ||||||
|  |         core_free(handle); | ||||||
|  |     return rc; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,51 @@ | ||||||
|  | /***************************************************************************
 | ||||||
|  |  *             __________               __   ___. | ||||||
|  |  *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___ | ||||||
|  |  *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 | ||||||
|  |  *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  < | ||||||
|  |  *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \ | ||||||
|  |  *                     \/            \/     \/    \/            \/ | ||||||
|  |  * $Id$ | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2021 Aidan MacDonald | ||||||
|  |  * | ||||||
|  |  * This program is free software; you can redistribute it and/or | ||||||
|  |  * modify it under the terms of the GNU General Public License | ||||||
|  |  * as published by the Free Software Foundation; either version 2 | ||||||
|  |  * of the License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||||||
|  |  * KIND, either express or implied. | ||||||
|  |  * | ||||||
|  |  ****************************************************************************/ | ||||||
|  | 
 | ||||||
|  | #ifndef __INSTALLER_FIIOM3K_H__ | ||||||
|  | #define __INSTALLER_FIIOM3K_H__ | ||||||
|  | 
 | ||||||
|  | #include <stddef.h> | ||||||
|  | 
 | ||||||
|  | #define INSTALL_SUCCESS                 0 | ||||||
|  | #define INSTALL_ERR_OUT_OF_MEMORY       (-1) | ||||||
|  | #define INSTALL_ERR_FILE_NOT_FOUND      (-2) | ||||||
|  | #define INSTALL_ERR_FILE_IO             (-3) | ||||||
|  | #define INSTALL_ERR_BAD_FORMAT          (-4) | ||||||
|  | #define INSTALL_ERR_NAND_OPEN           (-5) | ||||||
|  | #define INSTALL_ERR_NAND_IDENTIFY       (-6) | ||||||
|  | #define INSTALL_ERR_NAND_READ           (-7) | ||||||
|  | #define INSTALL_ERR_NAND_ENABLE_WRITES  (-8) | ||||||
|  | #define INSTALL_ERR_NAND_ERASE          (-9) | ||||||
|  | #define INSTALL_ERR_NAND_WRITE          (-10) | ||||||
|  | #define INSTALL_ERR_TAR_OPEN            (-11) | ||||||
|  | #define INSTALL_ERR_TAR_FIND            (-12) | ||||||
|  | #define INSTALL_ERR_TAR_READ            (-13) | ||||||
|  | #define INSTALL_ERR_MTAR(x,y)           ((INSTALL_ERR_##x)*100 + (y)) | ||||||
|  | #define INSTALL_ERR_FLASH(x,y)          ((INSTALL_ERR_##x)*100 + (y)) | ||||||
|  | 
 | ||||||
|  | /* Install the Rockbox bootloader from a bootloader.m3k image */ | ||||||
|  | extern int install_boot(const char* srcfile); | ||||||
|  | 
 | ||||||
|  | /* Backup or restore the bootloader from a raw NAND image */ | ||||||
|  | extern int backup_boot(const char* destfile); | ||||||
|  | extern int restore_boot(const char* srcfile); | ||||||
|  | 
 | ||||||
|  | #endif /* __INSTALLER_FIIOM3K_H__ */ | ||||||
|  | @ -25,6 +25,11 @@ | ||||||
| #include "system.h" | #include "system.h" | ||||||
| #include <string.h> | #include <string.h> | ||||||
| 
 | 
 | ||||||
|  | /* Available boot options */ | ||||||
|  | #define BOOTOPTION_ROCKBOX  0 | ||||||
|  | #define BOOTOPTION_ORIG_FW  1 | ||||||
|  | #define BOOTOPTION_RECOVERY 2 | ||||||
|  | 
 | ||||||
| /* Boot select button state must remain stable for this duration
 | /* Boot select button state must remain stable for this duration
 | ||||||
|  * before the choice will be accepted. Currently 100ms. |  * before the choice will be accepted. Currently 100ms. | ||||||
|  */ |  */ | ||||||
|  | @ -56,7 +61,7 @@ const struct spl_boot_option spl_boot_options[] = { | ||||||
|          */ |          */ | ||||||
|         .nand_addr = 0x6800, |         .nand_addr = 0x6800, | ||||||
|         .nand_size = 0x19800, |         .nand_size = 0x19800, | ||||||
|         .load_addr = X1000_DRAM_BASE - 8, /* first 8 bytes are bootloader ID */ |         .load_addr = X1000_DRAM_END - 0x19800, | ||||||
|         .exec_addr = X1000_DRAM_BASE, |         .exec_addr = X1000_DRAM_BASE, | ||||||
|         .cmdline = NULL, |         .cmdline = NULL, | ||||||
|     }, |     }, | ||||||
|  | @ -80,7 +85,7 @@ const struct spl_boot_option spl_boot_options[] = { | ||||||
| 
 | 
 | ||||||
| void spl_error(void) | void spl_error(void) | ||||||
| { | { | ||||||
|     const int pin = (1 << 24); |     const uint32_t pin = (1 << 24); | ||||||
| 
 | 
 | ||||||
|     /* Turn on button light */ |     /* Turn on button light */ | ||||||
|     jz_clr(GPIO_INT(GPIO_C), pin); |     jz_clr(GPIO_INT(GPIO_C), pin); | ||||||
|  | @ -105,6 +110,10 @@ int spl_get_boot_option(void) | ||||||
| 
 | 
 | ||||||
|     uint32_t pin = 1, lastpin = 0; |     uint32_t pin = 1, lastpin = 0; | ||||||
|     uint32_t deadline = 0; |     uint32_t deadline = 0; | ||||||
|  |     /* Iteration count guards against unlikely case of broken buttons
 | ||||||
|  |      * which never stabilize; if this occurs, we always boot Rockbox. */ | ||||||
|  |     int iter_count = 0; | ||||||
|  |     const int max_iter_count = 30; | ||||||
| 
 | 
 | ||||||
|     /* Configure the button GPIOs as inputs */ |     /* Configure the button GPIOs as inputs */ | ||||||
|     gpio_config(GPIO_A, pinmask, GPIO_INPUT); |     gpio_config(GPIO_A, pinmask, GPIO_INPUT); | ||||||
|  | @ -116,19 +125,18 @@ int spl_get_boot_option(void) | ||||||
|         if(pin != lastpin) { |         if(pin != lastpin) { | ||||||
|             /* This will always be set on the first iteration */ |             /* This will always be set on the first iteration */ | ||||||
|             deadline = __ost_read32() + BTN_STABLE_TIME; |             deadline = __ost_read32() + BTN_STABLE_TIME; | ||||||
|  |             iter_count += 1; | ||||||
|         } |         } | ||||||
|     } while(__ost_read32() < deadline); |     } while(iter_count < max_iter_count && __ost_read32() < deadline); | ||||||
| 
 | 
 | ||||||
|     /* Play button boots original firmware */ |     if(iter_count < max_iter_count && (pin & (1 << 17))) { | ||||||
|     if(pin == (1 << 17)) |         if(pin & (1 << 19)) | ||||||
|         return SPL_BOOTOPT_ORIG_FW; |             return BOOTOPTION_RECOVERY; /* Play+Volume Up */ | ||||||
| 
 |         else | ||||||
|     /* Volume up boots recovery */ |             return BOOTOPTION_ORIG_FW; /* Play */ | ||||||
|     if(pin == (1 << 19)) |     } else { | ||||||
|         return SPL_BOOTOPT_RECOVERY; |         return BOOTOPTION_ROCKBOX; /* Volume Up or no buttons */ | ||||||
| 
 |     } | ||||||
|     /* Default is to boot Rockbox */ |  | ||||||
|     return SPL_BOOTOPT_ROCKBOX; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void spl_handle_pre_boot(int bootopt) | void spl_handle_pre_boot(int bootopt) | ||||||
|  | @ -145,7 +153,7 @@ void spl_handle_pre_boot(int bootopt) | ||||||
|     /* System clock setup -- common to Rockbox and FiiO firmware
 |     /* System clock setup -- common to Rockbox and FiiO firmware
 | ||||||
|      * ---- |      * ---- | ||||||
|      * CPU at 1 GHz, L2 cache at 500 MHz |      * CPU at 1 GHz, L2 cache at 500 MHz | ||||||
|      * AHB0 and AHB2 and 200 MHz |      * AHB0 and AHB2 at 200 MHz | ||||||
|      * PCLK at 100 MHz |      * PCLK at 100 MHz | ||||||
|      * DDR at 200 MHz |      * DDR at 200 MHz | ||||||
|      */ |      */ | ||||||
|  | @ -153,7 +161,7 @@ void spl_handle_pre_boot(int bootopt) | ||||||
|     clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | CLKMUX_CPU(SCLK_A) | |     clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | CLKMUX_CPU(SCLK_A) | | ||||||
|                     CLKMUX_AHB0(SCLK_A) | CLKMUX_AHB2(SCLK_A)); |                     CLKMUX_AHB0(SCLK_A) | CLKMUX_AHB2(SCLK_A)); | ||||||
| 
 | 
 | ||||||
|     if(bootopt == SPL_BOOTOPT_ROCKBOX) { |     if(bootopt == BOOTOPTION_ROCKBOX) { | ||||||
|         /* We don't use MPLL in Rockbox, so switch DDR memory to APLL */ |         /* We don't use MPLL in Rockbox, so switch DDR memory to APLL */ | ||||||
|         clk_set_ddr(X1000_CLK_SCLK_A, 5); |         clk_set_ddr(X1000_CLK_SCLK_A, 5); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,29 +0,0 @@ | ||||||
| /***************************************************************************
 |  | ||||||
|  *             __________               __   ___. |  | ||||||
|  *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___ |  | ||||||
|  *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 |  | ||||||
|  *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  < |  | ||||||
|  *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \ |  | ||||||
|  *                     \/            \/     \/    \/            \/ |  | ||||||
|  * $Id$ |  | ||||||
|  * |  | ||||||
|  * Copyright (C) 2021 Aidan MacDonald |  | ||||||
|  * |  | ||||||
|  * This program is free software; you can redistribute it and/or |  | ||||||
|  * modify it under the terms of the GNU General Public License |  | ||||||
|  * as published by the Free Software Foundation; either version 2 |  | ||||||
|  * of the License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |  | ||||||
|  * KIND, either express or implied. |  | ||||||
|  * |  | ||||||
|  ****************************************************************************/ |  | ||||||
| 
 |  | ||||||
| #ifndef __SPL_TARGET_H__ |  | ||||||
| #define __SPL_TARGET_H__ |  | ||||||
| 
 |  | ||||||
| #define SPL_DDR_MEMORYSIZE  64 |  | ||||||
| #define SPL_DDR_AUTOSR_EN   1 |  | ||||||
| #define SPL_DDR_NEED_BYPASS 1 |  | ||||||
| 
 |  | ||||||
| #endif /* __SPL_TARGET_H__ */ |  | ||||||
|  | @ -1,27 +0,0 @@ | ||||||
| #ifndef __NAND_X1000_ERR_H__ |  | ||||||
| #define __NAND_X1000_ERR_H__ |  | ||||||
| 
 |  | ||||||
| /* Error codes which can be returned by the nand-x1000 API. These codes are
 |  | ||||||
|  * also used by host-side tools, so we define them here to avoid polluting |  | ||||||
|  * the namespace with useless X1000 APIs. */ |  | ||||||
| #define NANDERR_CHIP_UNSUPPORTED  (-1) |  | ||||||
| #define NANDERR_WRITE_PROTECTED   (-2) |  | ||||||
| #define NANDERR_UNALIGNED_ADDRESS (-3) |  | ||||||
| #define NANDERR_UNALIGNED_LENGTH  (-4) |  | ||||||
| #define NANDERR_READ_FAILED       (-5) |  | ||||||
| #define NANDERR_ECC_FAILED        (-6) |  | ||||||
| #define NANDERR_ERASE_FAILED      (-7) |  | ||||||
| #define NANDERR_PROGRAM_FAILED    (-8) |  | ||||||
| #define NANDERR_COMMAND_FAILED    (-9) |  | ||||||
| #define NANDERR_OTHER             (-99) |  | ||||||
| 
 |  | ||||||
| /* TEMPORARY -- compatibility hack for jztool's sake.
 |  | ||||||
|  * This will go away once the new bootloader gets merged */ |  | ||||||
| #define NAND_SUCCESS              0 |  | ||||||
| #define NAND_ERR_UNKNOWN_CHIP     NANDERR_CHIP_UNSUPPORTED |  | ||||||
| #define NAND_ERR_UNALIGNED        NANDERR_UNALIGNED_ADDRESS |  | ||||||
| #define NAND_ERR_WRITE_PROTECT    NANDERR_WRITE_PROTECTED |  | ||||||
| #define NAND_ERR_CONTROLLER       NANDERR_OTHER |  | ||||||
| #define NAND_ERR_COMMAND          NANDERR_COMMAND_FAILED |  | ||||||
| 
 |  | ||||||
| #endif /* __NAND_X1000_ERR_H__ */ |  | ||||||
|  | @ -200,11 +200,8 @@ static int nand_rdwr(bool write, uint32_t addr, uint32_t size, uint8_t* buf) | ||||||
|         return NAND_SUCCESS; |         return NAND_SUCCESS; | ||||||
|     if(write && !nand_drv.write_enabled) |     if(write && !nand_drv.write_enabled) | ||||||
|         return NAND_ERR_WRITE_PROTECT; |         return NAND_ERR_WRITE_PROTECT; | ||||||
|     /* FIXME: re-enable this check after merging new SPL+bootloader.
 |     if((uint32_t)buf & (CACHEALIGN_SIZE - 1)) | ||||||
|      * It's only necessary for DMA, which is currently not used, but it's a |         return NAND_ERR_UNALIGNED; | ||||||
|      * good practice anyway. Disable for now due to SPL complications. */ |  | ||||||
|     /*if((uint32_t)buf & (CACHEALIGN_SIZE - 1))
 |  | ||||||
|         return NAND_ERR_UNALIGNED;*/ |  | ||||||
| 
 | 
 | ||||||
|     addr >>= nand_drv.chip_data->log2_page_size; |     addr >>= nand_drv.chip_data->log2_page_size; | ||||||
|     size >>= nand_drv.chip_data->log2_page_size; |     size >>= nand_drv.chip_data->log2_page_size; | ||||||
|  |  | ||||||
|  | @ -36,7 +36,14 @@ | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <stddef.h> | #include <stddef.h> | ||||||
| #include "nand-x1000-err.h" | 
 | ||||||
|  | /* Error codes which can be returned by the NAND API */ | ||||||
|  | #define NAND_SUCCESS              0 | ||||||
|  | #define NAND_ERR_UNKNOWN_CHIP     (-1) | ||||||
|  | #define NAND_ERR_UNALIGNED        (-2) | ||||||
|  | #define NAND_ERR_WRITE_PROTECT    (-3) | ||||||
|  | #define NAND_ERR_CONTROLLER       (-4) | ||||||
|  | #define NAND_ERR_COMMAND          (-5) | ||||||
| 
 | 
 | ||||||
| /* Chip supports quad I/O for page read/write */ | /* Chip supports quad I/O for page read/write */ | ||||||
| #define NANDCHIP_FLAG_QUAD      0x01 | #define NANDCHIP_FLAG_QUAD      0x01 | ||||||
|  |  | ||||||
							
								
								
									
										97
									
								
								firmware/target/mips/ingenic_x1000/spl-start.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								firmware/target/mips/ingenic_x1000/spl-start.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,97 @@ | ||||||
|  | /*************************************************************************** | ||||||
|  |  *             __________               __   ___. | ||||||
|  |  *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___ | ||||||
|  |  *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  / | ||||||
|  |  *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  < | ||||||
|  |  *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \ | ||||||
|  |  *                     \/            \/     \/    \/            \/ | ||||||
|  |  * $Id$ | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2021 Aidan MacDonald | ||||||
|  |  * | ||||||
|  |  * This program is free software; you can redistribute it and/or
 | ||||||
|  |  * modify it under the terms of the GNU General Public License | ||||||
|  |  * as published by the Free Software Foundation; either version 2
 | ||||||
|  |  * of the License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||||||
|  |  * KIND, either express or implied. | ||||||
|  |  * | ||||||
|  |  ****************************************************************************/ | ||||||
|  | 
 | ||||||
|  | #include "config.h" | ||||||
|  | #include "mips.h" | ||||||
|  | 
 | ||||||
|  |     .text | ||||||
|  |     .extern spl_main
 | ||||||
|  |     .global _spl_start
 | ||||||
|  | 
 | ||||||
|  |     .set push
 | ||||||
|  |     .set mips32
 | ||||||
|  |     .set noreorder
 | ||||||
|  |     .set noat
 | ||||||
|  | 
 | ||||||
|  |     .section .init.spl | ||||||
|  | 
 | ||||||
|  | _spl_start: | ||||||
|  |     /* Clear data watchpoint */ | ||||||
|  |     mtc0    zero, C0_WATCHLO | ||||||
|  |     mtc0    zero, C0_WATCHHI | ||||||
|  | 
 | ||||||
|  |     /* Set BEV, ERL, mask interrupts */ | ||||||
|  |     li      v0, 0x40fc04 | ||||||
|  |     mtc0    v0, C0_Status | ||||||
|  | 
 | ||||||
|  |     /* Set Cause_IV to 1 (use special interrupt vector) */ | ||||||
|  |     li      v0, M_CauseIV | ||||||
|  |     mtc0    v0, C0_Cause | ||||||
|  | 
 | ||||||
|  |     /* Set CPU_MODE and BUS_MODE to 1 in CPM_OPCR (Ingenic does this) */ | ||||||
|  |     lui     v0, 0xb000 | ||||||
|  |     lw      v1, 0x24(v0) | ||||||
|  |     ori     v1, v1, 0x22 | ||||||
|  |     sw      v1, 0x24(v0) | ||||||
|  | 
 | ||||||
|  |     /* Enable kseg0 cacheability */ | ||||||
|  |     li      v0, 3 | ||||||
|  |     mtc0    v0, C0_Config | ||||||
|  |     nop | ||||||
|  | 
 | ||||||
|  |     /* According to ingenic: "enable idx-store-data cache insn" */ | ||||||
|  |     li      v0, 0x20000000 | ||||||
|  |     mtc0    v0, C0_ErrCtl | ||||||
|  | 
 | ||||||
|  |     /* Cache init */ | ||||||
|  |     li      v0, 0x80000000 | ||||||
|  |     ori     v1, v0, 0x4000 | ||||||
|  |     mtc0    zero, C0_TAGLO | ||||||
|  |     mtc0    zero, C0_TAGHI | ||||||
|  | _cache_loop: | ||||||
|  |     cache   ICIndexStTag, 0(v0) | ||||||
|  |     cache   DCIndexStTag, 0(v0) | ||||||
|  |     addiu   v0, v0, 32 | ||||||
|  |     bne     v0, v1, _cache_loop | ||||||
|  |     nop | ||||||
|  | 
 | ||||||
|  |     /* Invalidate BTB */ | ||||||
|  |     mfc0    v0, C0_Config, 7 | ||||||
|  |     nop | ||||||
|  |     ori     v0, v0, 2 | ||||||
|  |     mtc0    v0, C0_Config, 7 | ||||||
|  |     nop | ||||||
|  | 
 | ||||||
|  |     /* Clear the BSS segment (needed to zero-initialize C static values) */ | ||||||
|  |     la      t0, _bssbegin | ||||||
|  |     la      t1, _bssend | ||||||
|  |     beq     t0, t1, _bss_done | ||||||
|  | _bss_loop: | ||||||
|  |     addiu   t0, 4 | ||||||
|  |     bne     t0, t1, _bss_loop | ||||||
|  |     sw      zero, -4(t0) | ||||||
|  | _bss_done: | ||||||
|  | 
 | ||||||
|  |     /* Jump to C code */ | ||||||
|  |     j       spl_main | ||||||
|  |     nop | ||||||
|  | 
 | ||||||
|  |     .set pop
 | ||||||
|  | @ -1,66 +0,0 @@ | ||||||
| /***************************************************************************
 |  | ||||||
|  *             __________               __   ___. |  | ||||||
|  *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___ |  | ||||||
|  *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 |  | ||||||
|  *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  < |  | ||||||
|  *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \ |  | ||||||
|  *                     \/            \/     \/    \/            \/ |  | ||||||
|  * $Id$ |  | ||||||
|  * |  | ||||||
|  * Copyright (C) 2021 Aidan MacDonald |  | ||||||
|  * |  | ||||||
|  * This program is free software; you can redistribute it and/or |  | ||||||
|  * modify it under the terms of the GNU General Public License |  | ||||||
|  * as published by the Free Software Foundation; either version 2 |  | ||||||
|  * of the License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |  | ||||||
|  * KIND, either express or implied. |  | ||||||
|  * |  | ||||||
|  ****************************************************************************/ |  | ||||||
| 
 |  | ||||||
| #ifndef __SPL_X1000_DEFS_H__ |  | ||||||
| #define __SPL_X1000_DEFS_H__ |  | ||||||
| 
 |  | ||||||
| #include <stdint.h> |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| extern "C" { |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #define SPL_CMD_BOOT        0 |  | ||||||
| #define SPL_CMD_FLASH_READ  1 |  | ||||||
| #define SPL_CMD_FLASH_WRITE 2 |  | ||||||
| 
 |  | ||||||
| #define SPL_BOOTOPT_CHOOSE   0 |  | ||||||
| #define SPL_BOOTOPT_ROCKBOX  1 |  | ||||||
| #define SPL_BOOTOPT_ORIG_FW  2 |  | ||||||
| #define SPL_BOOTOPT_RECOVERY 3 |  | ||||||
| #define SPL_BOOTOPT_NONE     4 |  | ||||||
| 
 |  | ||||||
| #define SPL_FLAG_SKIP_INIT   (1 << 0) |  | ||||||
| 
 |  | ||||||
| #define SPL_MAX_SIZE          (12 * 1024) |  | ||||||
| #define SPL_LOAD_ADDRESS      0xf4001000 |  | ||||||
| #define SPL_EXEC_ADDRESS      0xf4001800 |  | ||||||
| #define SPL_ARGUMENTS_ADDRESS 0xf40011f0 |  | ||||||
| #define SPL_STATUS_ADDRESS    0xf40011e0 |  | ||||||
| #define SPL_BUFFER_ADDRESS    0xa0004000 |  | ||||||
| 
 |  | ||||||
| struct x1000_spl_arguments { |  | ||||||
|     uint32_t command; |  | ||||||
|     uint32_t param1; |  | ||||||
|     uint32_t param2; |  | ||||||
|     uint32_t flags; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct x1000_spl_status { |  | ||||||
|     int err_code; |  | ||||||
|     int reserved; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #endif /* __SPL_X1000_DEFS_H__ */ |  | ||||||
|  | @ -20,7 +20,6 @@ | ||||||
|  ****************************************************************************/ |  ****************************************************************************/ | ||||||
| 
 | 
 | ||||||
| #include "spl-x1000.h" | #include "spl-x1000.h" | ||||||
| #include "spl-target.h" |  | ||||||
| #include "clk-x1000.h" | #include "clk-x1000.h" | ||||||
| #include "nand-x1000.h" | #include "nand-x1000.h" | ||||||
| #include "system.h" | #include "system.h" | ||||||
|  | @ -29,16 +28,15 @@ | ||||||
| #include "x1000/ddrc.h" | #include "x1000/ddrc.h" | ||||||
| #include "x1000/ddrc_apb.h" | #include "x1000/ddrc_apb.h" | ||||||
| #include "x1000/ddrphy.h" | #include "x1000/ddrphy.h" | ||||||
|  | #include "ucl_decompress.h" | ||||||
| 
 | 
 | ||||||
| struct x1000_spl_arguments* const spl_arguments = | #ifdef FIIO_M3K | ||||||
|     (struct x1000_spl_arguments*)SPL_ARGUMENTS_ADDRESS; | # define SPL_DDR_MEMORYSIZE  64 | ||||||
| 
 | # define SPL_DDR_AUTOSR_EN   1 | ||||||
| struct x1000_spl_status* const spl_status = | # define SPL_DDR_NEED_BYPASS 1 | ||||||
|     (struct x1000_spl_status*)SPL_STATUS_ADDRESS; | #else | ||||||
| 
 | # error "please add SPL memory definitions" | ||||||
| /* defined to be Linux compatible; Rockbox needs no arguments so there
 | #endif | ||||||
|  * is no harm in passing them and we save a little code size */ |  | ||||||
| typedef void(*entry_fn)(int, char**, int, int); |  | ||||||
| 
 | 
 | ||||||
| /* Note: This is based purely on disassembly of the SPL from the FiiO M3K.
 | /* Note: This is based purely on disassembly of the SPL from the FiiO M3K.
 | ||||||
|  * The code there is somewhat generic and corresponds roughly to Ingenic's |  * The code there is somewhat generic and corresponds roughly to Ingenic's | ||||||
|  | @ -243,83 +241,70 @@ static int nandread(uint32_t addr, uint32_t size, void* buffer) | ||||||
|     return rc; |     return rc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int nandwrite(uint32_t addr, uint32_t size, const void* buffer) | /* Entry point function type, defined to be Linux compatible. */ | ||||||
| { | typedef void(*entry_fn)(int, char**, int, int); | ||||||
|     int rc; |  | ||||||
|     int mf_id, dev_id; |  | ||||||
| 
 |  | ||||||
|     if((rc = nand_open())) |  | ||||||
|         return rc; |  | ||||||
|     if((rc = nand_identify(&mf_id, &dev_id))) { |  | ||||||
|         nand_close(); |  | ||||||
|         return rc; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if((rc = nand_enable_writes(true))) |  | ||||||
|         goto _end; |  | ||||||
| 
 |  | ||||||
|     if((rc = nand_erase(addr, size))) |  | ||||||
|         goto _end1; |  | ||||||
| 
 |  | ||||||
|     rc = nand_write(addr, size, (const uint8_t*)buffer); |  | ||||||
| 
 |  | ||||||
|   _end1: |  | ||||||
|     /* an error here is very unlikely, so ignore it */ |  | ||||||
|     nand_enable_writes(false); |  | ||||||
| 
 |  | ||||||
|   _end: |  | ||||||
|     nand_close(); |  | ||||||
|     return rc; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| /* Kernel command line arguments */ | /* Kernel command line arguments */ | ||||||
| static char* argv[2]; | static char* argv[2]; | ||||||
| 
 | 
 | ||||||
| void main(void) | /* This variable is defined by the maskrom. It's simply the level of the
 | ||||||
|  |  * boot_sel[2:0] pins (GPIOs B28-30) at boot time. Meaning of the bits: | ||||||
|  |  * | ||||||
|  |  * boot_sel[2] boot_sel[1] boot_sel[0]      Description | ||||||
|  |  * ----------------------------------------------------------------- | ||||||
|  |  * 1           X           X                EXCLK is 26 MHz | ||||||
|  |  * 0           X           X                EXCLK is 24 MHz | ||||||
|  |  * X           1           1                Boot from SFC0 | ||||||
|  |  * X           0           1                Boot from MSC0 | ||||||
|  |  * X           1           0                Boot from USB 2.0 device | ||||||
|  |  * ----------------------------------------------------------------- | ||||||
|  |  * Source: X1000 PM pg. 687, "XBurst Boot ROM Specification" | ||||||
|  |  */ | ||||||
|  | extern const uint32_t boot_sel; | ||||||
|  | 
 | ||||||
|  | void spl_main(void) | ||||||
| { | { | ||||||
|     if(!(SPL_ARGUMENTS->flags & SPL_FLAG_SKIP_INIT)) |     int opt_index; | ||||||
|         init(); |     uint8_t* load_addr; | ||||||
|  |     const struct spl_boot_option* opt; | ||||||
| 
 | 
 | ||||||
|     switch(SPL_ARGUMENTS->command) { |     /* Basic hardware init */ | ||||||
|     case SPL_CMD_BOOT: { |     init(); | ||||||
|         int option = SPL_ARGUMENTS->param1; |  | ||||||
|         if(option == SPL_BOOTOPT_CHOOSE) |  | ||||||
|             option = spl_get_boot_option(); |  | ||||||
|         if(option == SPL_BOOTOPT_NONE) |  | ||||||
|             return; |  | ||||||
| 
 | 
 | ||||||
|         const struct spl_boot_option* opt = &spl_boot_options[option-1]; |     /* If doing a USB boot, host PC will upload 2nd stage itself,
 | ||||||
|         if(nandread(opt->nand_addr, opt->nand_size, (void*)opt->load_addr)) |      * we should not load anything from flash or change clocks. */ | ||||||
|  |     if((boot_sel & 3) == 2) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     /* Get the boot option */ | ||||||
|  |     opt_index = spl_get_boot_option(); | ||||||
|  |     opt = &spl_boot_options[opt_index]; | ||||||
|  |     load_addr = (uint8_t*)opt->load_addr; | ||||||
|  | 
 | ||||||
|  |     /* Set up hardware, load stuff from flash */ | ||||||
|  |     spl_handle_pre_boot(opt_index); | ||||||
|  |     if(nandread(opt->nand_addr, opt->nand_size, load_addr)) | ||||||
|  |         spl_error(); | ||||||
|  | 
 | ||||||
|  |     if(!opt->cmdline) { | ||||||
|  |         /* No command line => we are booting Rockbox, decompress bootloader.
 | ||||||
|  |          * In the case of Rockbox, load binary directly to exec address */ | ||||||
|  |         uint32_t out_size = X1000_DRAM_END - opt->exec_addr; | ||||||
|  |         int rc = ucl_unpack(load_addr, opt->nand_size, | ||||||
|  |                             (uint8_t*)opt->exec_addr, &out_size); | ||||||
|  |         if(rc != UCL_E_OK) | ||||||
|             spl_error(); |             spl_error(); | ||||||
| 
 |  | ||||||
|         /* Let target handle necessary pre-boot setup */ |  | ||||||
|         spl_handle_pre_boot(option); |  | ||||||
| 
 |  | ||||||
|         /* Reading the Linux command line from the bootloader is handled by
 |  | ||||||
|          * arch/mips/xburst/core/prom.c -- see Ingenic kernel sources. |  | ||||||
|          * |  | ||||||
|          * Rockbox doesn't use arguments, but passing them does not hurt and it |  | ||||||
|          * saves an unnecessary branch. |  | ||||||
|          */ |  | ||||||
|         entry_fn entry = (entry_fn)opt->exec_addr; |  | ||||||
|         argv[0] = 0; |  | ||||||
|         argv[1] = (char*)opt->cmdline; |  | ||||||
| 
 |  | ||||||
|         commit_discard_idcache(); |  | ||||||
|         entry(2, argv, 0, 0); |  | ||||||
|         __builtin_unreachable(); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     case SPL_CMD_FLASH_READ: |     /* Reading the Linux command line from the bootloader is handled by
 | ||||||
|         SPL_STATUS->err_code = nandread(SPL_ARGUMENTS->param1, |      * arch/mips/xburst/core/prom.c -- see Ingenic kernel sources. It's | ||||||
|                                         SPL_ARGUMENTS->param2, |      * simply an (int argc, char* argv[]) thing. | ||||||
|                                         (void*)SPL_BUFFER_ADDRESS); |      */ | ||||||
|         return; |     entry_fn entry = (entry_fn)opt->exec_addr; | ||||||
|  |     argv[0] = 0; | ||||||
|  |     argv[1] = (char*)opt->cmdline; | ||||||
| 
 | 
 | ||||||
|     case SPL_CMD_FLASH_WRITE: |     commit_discard_idcache(); | ||||||
|         SPL_STATUS->err_code = nandwrite(SPL_ARGUMENTS->param1, |     entry(2, argv, 0, 0); | ||||||
|                                          SPL_ARGUMENTS->param2, |     __builtin_unreachable(); | ||||||
|                                          (const void*)SPL_BUFFER_ADDRESS); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -22,10 +22,7 @@ | ||||||
| #ifndef __SPL_X1000_H__ | #ifndef __SPL_X1000_H__ | ||||||
| #define __SPL_X1000_H__ | #define __SPL_X1000_H__ | ||||||
| 
 | 
 | ||||||
| #include "spl-x1000-defs.h" | #include <stdint.h> | ||||||
| 
 |  | ||||||
| #define SPL_ARGUMENTS ((struct x1000_spl_arguments*)SPL_ARGUMENTS_ADDRESS) |  | ||||||
| #define SPL_STATUS    ((struct x1000_spl_status*)SPL_STATUS_ADDRESS) |  | ||||||
| 
 | 
 | ||||||
| struct spl_boot_option { | struct spl_boot_option { | ||||||
|     uint32_t nand_addr; |     uint32_t nand_addr; | ||||||
|  | @ -35,15 +32,13 @@ struct spl_boot_option { | ||||||
|     const char* cmdline; /* for Linux */ |     const char* cmdline; /* for Linux */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* Defined by target, indices are 0 = ROCKBOX, 1 = ORIG_FW, etc... */ | /* Defined by target, order is not important */ | ||||||
| extern const struct spl_boot_option spl_boot_options[]; | extern const struct spl_boot_option spl_boot_options[]; | ||||||
| 
 | 
 | ||||||
| /* Called on a fatal error */ | /* Called on a fatal error */ | ||||||
| extern void spl_error(void) __attribute__((noreturn)); | extern void spl_error(void) __attribute__((noreturn)); | ||||||
| 
 | 
 | ||||||
| /* When SPL boots with SPL_BOOTOPTION_CHOOSE, this function is invoked
 | /* Invoked by SPL main routine to determine the boot option */ | ||||||
|  * to let the target figure out the boot option based on buttons the |  | ||||||
|  * user is pressing */ |  | ||||||
| extern int spl_get_boot_option(void); | extern int spl_get_boot_option(void); | ||||||
| 
 | 
 | ||||||
| /* Do any setup/initialization needed for the given boot option, this
 | /* Do any setup/initialization needed for the given boot option, this
 | ||||||
|  |  | ||||||
|  | @ -3,8 +3,8 @@ | ||||||
| 
 | 
 | ||||||
| OUTPUT_FORMAT("elf32-littlemips") | OUTPUT_FORMAT("elf32-littlemips") | ||||||
| OUTPUT_ARCH(MIPS) | OUTPUT_ARCH(MIPS) | ||||||
| ENTRY(_start) | ENTRY(_spl_start) | ||||||
| STARTUP(target/mips/ingenic_x1000/crt0.o) | STARTUP(target/mips/ingenic_x1000/spl-start.o) | ||||||
| 
 | 
 | ||||||
| MEMORY { | MEMORY { | ||||||
|     /* First 4k of TCSM is used by mask ROM for stack + variables, |     /* First 4k of TCSM is used by mask ROM for stack + variables, | ||||||
|  | @ -15,9 +15,12 @@ MEMORY { | ||||||
| 
 | 
 | ||||||
| SECTIONS | SECTIONS | ||||||
| { | { | ||||||
|  |     /* Mask ROM variables, addresses found by disassembly */ | ||||||
|  |     boot_sel = X1000_TCSM_BASE + 0x1ec; | ||||||
|  | 
 | ||||||
|     .text : |     .text : | ||||||
|     { |     { | ||||||
|         *(.init.text); |         *(.init.spl); | ||||||
|         *(.text*); |         *(.text*); | ||||||
|         *(.icode*); |         *(.icode*); | ||||||
|     } > TCSM |     } > TCSM | ||||||
|  |  | ||||||
							
								
								
									
										53
									
								
								firmware/target/mips/ingenic_x1000/x1000boot.make
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								firmware/target/mips/ingenic_x1000/x1000boot.make
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,53 @@ | ||||||
|  | #             __________               __   ___. | ||||||
|  | #   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___ | ||||||
|  | #   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  / | ||||||
|  | #   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  < | ||||||
|  | #   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \ | ||||||
|  | #                     \/            \/     \/    \/            \/ | ||||||
|  | # $Id$ | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | INCLUDES += -I$(APPSDIR) | ||||||
|  | SRC += $(call preprocess, $(APPSDIR)/SOURCES) | ||||||
|  | 
 | ||||||
|  | LDSDEP := $(FIRMDIR)/export/cpu.h $(FIRMDIR)/export/config/$(MODELNAME).h | ||||||
|  | 
 | ||||||
|  | BOOTLDS := $(FIRMDIR)/target/$(CPU)/$(MANUFACTURER)/boot.lds | ||||||
|  | BOOTLINK := $(BUILDDIR)/boot.link | ||||||
|  | 
 | ||||||
|  | SPLLDS := $(FIRMDIR)/target/$(CPU)/$(MANUFACTURER)/spl.lds | ||||||
|  | SPLLINK := $(BUILDDIR)/spl.link | ||||||
|  | 
 | ||||||
|  | CLEANOBJS += $(BUILDDIR)/bootloader.* $(BUILDDIR)/spl.* | ||||||
|  | 
 | ||||||
|  | include $(FIRMDIR)/target/$(CPU)/$(MANUFACTURER)/$(MODELNAME)/boot.make | ||||||
|  | 
 | ||||||
|  | .SECONDEXPANSION: | ||||||
|  | 
 | ||||||
|  | $(BOOTLINK): $(BOOTLDS) $(LDSDEP) | ||||||
|  | 	$(call PRINTS,PP $(@F)) | ||||||
|  | 	$(call preprocess2file,$<,$@,) | ||||||
|  | 
 | ||||||
|  | $(BUILDDIR)/bootloader.elf: $$(OBJ) $(FIRMLIB) $(CORE_LIBS) $$(BOOTLINK) | ||||||
|  | 	$(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -Os -nostdlib -o $@ $(OBJ) \ | ||||||
|  | 		-L$(BUILDDIR)/firmware -lfirmware \ | ||||||
|  | 		-L$(BUILDDIR)/lib $(call a2lnk, $(CORE_LIBS)) \ | ||||||
|  | 		-lgcc -T$(BOOTLINK) $(GLOBAL_LDOPTS) \ | ||||||
|  | 		-Wl,--gc-sections -Wl,-Map,$(BUILDDIR)/bootloader.map | ||||||
|  | 
 | ||||||
|  | $(BUILDDIR)/bootloader.bin: $(BUILDDIR)/bootloader.elf | ||||||
|  | 	$(call PRINTS,OC $(@F))$(call objcopy,$<,$@) | ||||||
|  | 
 | ||||||
|  | $(SPLLINK): $(SPLLDS) $(LDSDEP) | ||||||
|  | 	$(call PRINTS,PP $(@F)) | ||||||
|  | 	$(call preprocess2file,$<,$@,) | ||||||
|  | 
 | ||||||
|  | $(BUILDDIR)/spl.elf: $$(OBJ) $(FIRMLIB) $(CORE_LIBS) $$(SPLLINK) | ||||||
|  | 	$(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -Os -nostdlib -o $@ $(OBJ) \ | ||||||
|  | 		-L$(BUILDDIR)/firmware -lfirmware \ | ||||||
|  | 		-L$(BUILDDIR)/lib $(call a2lnk, $(CORE_LIBS)) \ | ||||||
|  | 		-lgcc -T$(SPLLINK) $(GLOBAL_LDOPTS) \ | ||||||
|  | 		-Wl,--gc-sections -Wl,-Map,$(BUILDDIR)/spl.map | ||||||
|  | 
 | ||||||
|  | $(BUILDDIR)/spl.bin: $(BUILDDIR)/spl.elf | ||||||
|  | 	$(call PRINTS,OC $(@F))$(call objcopy,$<,$@) | ||||||
							
								
								
									
										21
									
								
								tools/configure
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								tools/configure
									
										
									
									
										vendored
									
									
								
							|  | @ -1624,7 +1624,8 @@ fi | ||||||
|   genericbitmaptools="$toolset bmp2rb" |   genericbitmaptools="$toolset bmp2rb" | ||||||
|   # scramble is used by all other targets |   # scramble is used by all other targets | ||||||
|   scramblebitmaptools="$genericbitmaptools scramble" |   scramblebitmaptools="$genericbitmaptools scramble" | ||||||
| 
 |   # used by X1000 targets | ||||||
|  |   x1000tools="$genericbitmaptools scramble mkspl-x1000 uclpack" | ||||||
| 
 | 
 | ||||||
|   #  ---- For each target ---- |   #  ---- For each target ---- | ||||||
|   # |   # | ||||||
|  | @ -4100,15 +4101,13 @@ fi | ||||||
|     appextra="recorder:gui" |     appextra="recorder:gui" | ||||||
|     plugins="yes" |     plugins="yes" | ||||||
|     tool="$rootdir/tools/scramble -add=fiiom3k " |     tool="$rootdir/tools/scramble -add=fiiom3k " | ||||||
|     boottool="$rootdir/tools/scramble -add=fiiom3k " |     boottool="" # not used | ||||||
|     spltool="$rootdir/tools/mkspl-x1000 -type=nand -ppb=2 -bpp=2 " |  | ||||||
|     output="rockbox.m3k" |     output="rockbox.m3k" | ||||||
|     bootoutput="bootloader.m3k" |     bootoutput="bootloader.m3k" | ||||||
|     sploutput="spl.m3k" |  | ||||||
|     sysfontbl="16-Terminus" |     sysfontbl="16-Terminus" | ||||||
|     # toolset is the tools within the tools directory that we build for |     # toolset is the tools within the tools directory that we build for | ||||||
|     # this particular target. |     # this particular target. | ||||||
|     toolset="$toolset mkspl-x1000" |     toolset="$x1000tools" | ||||||
|     bmp2rb_mono="$rootdir/tools/bmp2rb -f 0" |     bmp2rb_mono="$rootdir/tools/bmp2rb -f 0" | ||||||
|     bmp2rb_native="$rootdir/tools/bmp2rb -f 4" |     bmp2rb_native="$rootdir/tools/bmp2rb -f 4" | ||||||
|     # architecture, manufacturer and model for the target-tree build |     # architecture, manufacturer and model for the target-tree build | ||||||
|  | @ -4187,9 +4186,6 @@ case $modelname in | ||||||
|   sansae200) |   sansae200) | ||||||
|      gdbstub=", (E)raser" |      gdbstub=", (E)raser" | ||||||
|      ;; |      ;; | ||||||
|   fiiom3k) |  | ||||||
|      gdbstub=", (X) SPL loader" |  | ||||||
|      ;; |  | ||||||
|   *) |   *) | ||||||
|      ;; |      ;; | ||||||
| esac | esac | ||||||
|  | @ -4215,15 +4211,6 @@ fi | ||||||
|       bootloader="1" |       bootloader="1" | ||||||
|       echo "sansa eraser build selected" |       echo "sansa eraser build selected" | ||||||
|       ;; |       ;; | ||||||
|     [Xx]) |  | ||||||
|       appsdir='$(ROOTDIR)/bootloader' |  | ||||||
|       apps="bootloader" |  | ||||||
|       extradefines="$extradefines -DBOOTLOADER -DBOOTLOADER_SPL -ffunction-sections -fdata-sections" |  | ||||||
|       bootloader="1" |  | ||||||
|       tool="$spltool" |  | ||||||
|       output="$sploutput" |  | ||||||
|       echo "SPL bootloader build selected" |  | ||||||
|       ;; |  | ||||||
|     [Bb]) |     [Bb]) | ||||||
|       appsdir='$(ROOTDIR)/bootloader' |       appsdir='$(ROOTDIR)/bootloader' | ||||||
|       apps="bootloader" |       apps="bootloader" | ||||||
|  |  | ||||||
|  | @ -109,6 +109,8 @@ ifneq (,$(findstring bootloader,$(APPSDIR))) | ||||||
|     include $(ROOTDIR)/firmware/target/hosted/aigo/erosq.make |     include $(ROOTDIR)/firmware/target/hosted/aigo/erosq.make | ||||||
|   else ifneq (,$(findstring fiio,$(APP_TYPE))) |   else ifneq (,$(findstring fiio,$(APP_TYPE))) | ||||||
|     include $(ROOTDIR)/firmware/target/hosted/fiio/fiio.make |     include $(ROOTDIR)/firmware/target/hosted/fiio/fiio.make | ||||||
|  |   else ifneq (,$(findstring ingenic_x1000,$(MANUFACTURER))) | ||||||
|  |     include $(ROOTDIR)/firmware/target/mips/ingenic_x1000/x1000boot.make | ||||||
|   else |   else | ||||||
|     include $(APPSDIR)/bootloader.make |     include $(APPSDIR)/bootloader.make | ||||||
|   endif |   endif | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue