blob: 67d5aa95ddb880418fd3049bf7ec204b9681f8f3 [file] [log] [blame] [edit]
/*
* Copyright 2008 - 2009 Windriver, <www.windriver.com>
* Author: Tom Rix <Tom.Rix@windriver.com>
*
* (C) Copyright 2014 Linaro, Ltd.
* Rob Herring <robh@kernel.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <command.h>
#include <fb_fastboot.h>
#include <g_dnl.h>
// Fastboot main loop.
//
// |host_connect_timeout_ms|: timeout in milliseconds. If no host USB connection
// has been made in this time, exit fastboot mode. Set to 0 to disable timeout.
//
// Returns CMD_RET_SUCCESS on exit whether timeout occurred or not.
static int fastboot_loop(int host_connect_timeout_ms)
{
int ret;
g_dnl_clear_detach();
ret = g_dnl_register("usb_dnl_fastboot");
if (ret)
return ret;
uint64_t start_ticks = get_ticks();
uint64_t wait_ticks = host_connect_timeout_ms * (get_tbclk() / 1000);
while (1) {
if (g_dnl_detach())
break;
if (ctrlc())
break;
usb_gadget_handle_interrupts();
if (host_connect_timeout_ms && !fastboot_host_connected &&
(get_ticks() - start_ticks) > wait_ticks) {
printf("Host USB connection not detected, exiting fastboot\n");
break;
}
}
g_dnl_unregister();
g_dnl_clear_detach();
return CMD_RET_SUCCESS;
}
static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
return fastboot_loop(0);
}
static int do_fastboot_if_host_connected(cmd_tbl_t *cmdtp, int flag, int argc,
char *const argv[])
{
// Experimentally, 500ms seems too short and will sometimes exit before the
// USB connection initializes, but 1s seems to work consistently on Linux. We
// set it to 2s here just to be extra safe so it works for all hosts - the delay
// only takes effect if fastboot was requested but no USB cable is connected,
// so it's OK to overshoot here.
return fastboot_loop(2000);
}
U_BOOT_CMD(fastboot, 1, 0, do_fastboot, "use USB Fastboot protocol",
"\n"
" - run as a fastboot usb device");
// We give this a separate command rather than making timeout a parameter
// because we should decide a common timeout value here rather than passing
// it in, and to make the call site less ambiguous since newer versions of
// u-boot pass in the USB interface number as a param to `fastboot`.
U_BOOT_CMD(
fastboot_if_host_connected, 1, 0, do_fastboot_if_host_connected,
"use USB Fastboot protocol if a USB host is connected",
"\n"
" - run as a fastboot usb device but exit if a host isn't detected");
__attribute__((weak)) bool force_fastboot_mode(void);
/*
* Checks whether forced switching into fastboot mode is requested
* Returns 0 if requested, 1 - otherwise.
*/
static int do_force_fastboot_mode(cmd_tbl_t *cmdtp, int flag, int argc,
char *const argv[])
{
if (force_fastboot_mode) {
if (force_fastboot_mode()) {
printf("Force Fastboot mode: on\n");
return 0;
}
printf("Force Fastboot mode: off\n");
} else {
printf("Force Fastboot mode is not supported.\n");
}
return 1;
}
U_BOOT_CMD(force_fastboot_mode, 1, 0, do_force_fastboot_mode,
"check if USB Fastboot mode should be forced", "");