u-boot/u-boot/board/ar7240/common/usb_boot.c

200 lines
5.1 KiB
C

/*
* USB boot functions for Carambola2
*
* Copyright (C) 2014 Mantas Pucka <mantas@8devices.com>
*
* SPDX-License-Identifier:GPL-2.0
*/
#include <common.h>
#include <command.h>
#include <part.h>
#include <usb.h>
#include <fs.h>
#include <fat.h>
#define XMK_STR(x) #x
#define MK_STR(x) XMK_STR(x)
void usbboot_indicate_recovery(int type)
{
// type=0 - before recovery
// type=1 - after recovery
int cnt = 4; // how many times to blink
if (type) cnt=2;
while(cnt--){
ar7240_gpio_led_switch(3, 1);
mdelay(500);
ar7240_gpio_led_switch(3, 0);
mdelay(500);
}
if (!type) mdelay(500); //wait 0.5s after last blink before recovery
}
int usbboot_boot(char * boot_dev_part, char * boot_file_name)
{
int fat_read_ret;
char* bootm_argv[] = {"bootm", MK_STR(CFG_USB_BOOT_LOAD_ADDR)};
fs_set_blk_dev ("usb", boot_dev_part, FS_TYPE_FAT);
fat_read_ret = do_fat_read_at(boot_file_name,
0,
CFG_USB_BOOT_LOAD_ADDR,
CFG_MAX_USB_BOOT_FILE_SIZE,
0);
if (fat_read_ret > 0){
printf ("Booting image %s (%d bytes) from usb device %s \n",
boot_file_name , fat_read_ret, boot_dev_part);
do_bootm(NULL, 0 , 2, bootm_argv);
}
return -1; //Boot failed
}
int usbboot_recovery(char * boot_dev_part, char * boot_file_name)
{
int fat_read_ret;
char flash_cmd [128];
char image_size[16];
fs_set_blk_dev ("usb", boot_dev_part, FS_TYPE_FAT);
fat_read_ret = do_fat_read_at(boot_file_name,
0,
CFG_USB_BOOT_LOAD_ADDR,
CFG_MAX_USB_RECOVERY_FILE_SIZE,
0);
if (fat_read_ret > 0){
usbboot_indicate_recovery(0);
//TODO: check image??
printf ("Flashing image %s (%d bytes) from usb device %s \n",
boot_file_name , fat_read_ret, boot_dev_part);
sprintf(image_size,"%x",fat_read_ret);
// Example command
//erase 0x9f050000 +3FA000; cp.b 0x80060000 0x9f050000 3FA000
char* load_addr = MK_STR(CFG_USB_BOOT_LOAD_ADDR);
sprintf(flash_cmd,"erase %s +%s; cp.b %s %s %s",
CFG_USB_RECOVERY_FW_START_IN_FLASH,
image_size,
load_addr,
CFG_USB_RECOVERY_FW_START_IN_FLASH,
image_size);
printf ("\nFlashing image\n%s\n", flash_cmd);
setenv("recovery_flash_cmd", flash_cmd);
int argc_flash=2;
char* argv_flash[]={"run", "recovery_flash_cmd"};
cmd_tbl_t *cmdtp=NULL;
int flash_ret = do_run ( cmdtp, 0, argc_flash, argv_flash);
printf ("\nFlashing sucsessful. Remove USB storage with recovery image.");
usbboot_indicate_recovery(1);
do_reset(NULL, 0, 0, NULL);
}
return -1; //Boot failed
}
int usbboot_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int i;
char part_id[8];
block_dev_desc_t *stor_dev = NULL;
disk_partition_t *info = NULL;
char* boot_file_name; //Can include directories eg. "boot/vmlinux.uimage"
char* recovery_file_name;
char* boot_dev_part;
/* boot_dev_part format "<usb device>:<partition>",
* eg. "0:1" - frst usb storage device's first partition
* */
boot_file_name = getenv ("bootfile");
if (boot_file_name == NULL)
boot_file_name = CFG_USB_BOOT_FILENAME;
recovery_file_name = getenv ("recoveryfile");
if (recovery_file_name == NULL)
recovery_file_name = CFG_USB_RECOVERY_FILENAME;
boot_dev_part = getenv ("bootdev");
usb_stop();
if (usb_init() < 0)
return -1;
/* try to recognize storage devices immediately */
usb_stor_scan(0);
int devno = 0;
//if given device name just boot it
if (boot_dev_part != NULL){
usbboot_recovery(boot_dev_part, recovery_file_name);
usbboot_boot(boot_dev_part, boot_file_name);
return -2; //if returns, means boot failed
}
// scan all devices and partitions for boot image
for (devno = 0; ; ++devno) {
stor_dev = usb_stor_get_dev(devno);
if (stor_dev == NULL)
break;
//try boot from full device (no partitions)
sprintf(part_id,"%d:%d", devno, 0);
usbboot_recovery(part_id, recovery_file_name);
usbboot_boot(part_id, boot_file_name);
//scan partitions
if (stor_dev->part_type != PART_TYPE_DOS)
continue;
for (i=1; i<=CFG_USB_BOOT_MAX_PARTITIONS_SCAN; i++){
printf("start %d size %d name %s\n", info->start, info->size, info->name);
printf("SCANNING device %d\n",i);
if (get_partition_info_dos(stor_dev, i, info) == 0){
sprintf(part_id,"%d:%d", devno, i);
usbboot_recovery(part_id, recovery_file_name);
usbboot_boot(part_id, boot_file_name);
}
}
}
printf ("Boot or recovery image (%s or %s) not found in usb storage\n", boot_file_name, recovery_file_name);
return -1;
}
void do_usb_boot (void){
char* boot_mode;
int s_force=0, s_gpio=0, s_never = 0;
boot_mode = getenv ("usbboot");
if (boot_mode != NULL){
s_force = !(strcmp(boot_mode, "force"));
s_gpio = !(strcmp(boot_mode, "gpio"));
s_never = !(strcmp(boot_mode, "never"));
}
if ( (s_force && s_never == 0) || (boot_mode == NULL))
s_gpio = 1;
if (s_never){
printf("USB boot is disabled in environment\n");
return;
}
if (s_force){
printf("USB boot is forced in environment\n");
usbboot_scan(0,0,0,0);
}
if ( s_gpio ){
debug("USB GPIO: %d\n", button_read(CFG_USB_BOOT_BUTTON_ID));
if (button_read(CFG_USB_BOOT_BUTTON_ID)==1)
usbboot_scan(0,0,0,0);
}
}
U_BOOT_CMD(
usb_boot_file, 5, 1, usbboot_scan,
"usb_boot_file - Automatic boot/recovery from file in USB drive\n",
" "
);