/*
 * Copyright (C) 2012, 2013 sysmocom s.f.m.c. GmbH
 * Author: Holger Hans Peter Freyther

 * 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 program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <config.h>
#include <common.h>
#include <command.h>
#include <status_led.h>
#include <asm-generic/gpio.h>

#define BLINK_LED

static int enable_netconsole(void)
{
	printf("Enabling the network console.\n");

	/* reset in 60s if it is not interrupted */
	return run_command("setenv stdout nc; setenv stdin nc", 0);
}

static int env_failed(void)
{
	printf("Environment clearing failed.\n");

	BLINK_LED(7);
	return -1;
}

static int dhcp_failed(void)
{
	printf("DHCP failed. Giving up on recovery.\n");

	BLINK_LED(10);
	return -1;
}

static int tftp_failed(void)
{
	printf("TFTP failed.\n");	
	BLINK_LED(13);
	enable_netconsole();
	return -1;
}

static int flash_failed(void)
{
	printf("Flash failed.\n");
	BLINK_LED(15);
	enable_netconsole();
	return -1;
}

/**
 * This will run the recovery process.
 * 1.) Enable the LED to give instant feedback.
 * 2.) Clear the environment in case of bad configuration.
 * 3.) Get a DHCP lease.
 * 4.) Try to tftpboot
 * 5.) Try to tftpboot with a different server
 * 6.) Flash
 * 7.) Reset or enter netconsole
 */
static int do_run_recovery(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
	int rc;

	//status_led_set(0, STATUS_LED_ON);
	printf("Starting the recovery process.\n");

	/* Wait a bit and check if the reset button is still pressed */
	if (argc == 2 && strcmp(argv[1], "force") == 0) {
		printf("Forcing the recovery process.\n");
	}

	BLINK_LED(5);
	//status_led_set(0, STATUS_LED_ON);

	/* erase u-boot enviroment */
	rc = run_command("erase 0x9f040000 +0x10000", 0);
	if (rc < 0)
		return env_failed();

	rc = run_command("setenv autoload no; set netretry no; dhcp", 0);
	if (rc < 0)
		return dhcp_failed();

	rc = run_command("setenv filesize 0; "
			 "tftp 0x81000000 " RECOVERY_FILENAME_STRING, 0);
	if (rc < 0) {
		rc = run_command("setenv filesize 0; "
				 "set serverip 255.255.255.255; "
				 "tftp 0x81000000 " RECOVERY_FILENAME_STRING, 0);
	}

	if (rc < 0)
		return tftp_failed();

	rc = run_command("erase 0x9f050000 +0x7a0000; "
			 "cp.b 0x81000000 0x9f050000 0x7a0000", 0);
	if (rc < 0)
		return flash_failed();

	return run_command("resetcycle; reset", 0);
}

U_BOOT_CMD(
	run_recovery, 2, 0, do_run_recovery,
	"run_recovery - Run the sysmocom sysmoBTS recovery process",
	"[force]"
);
