Merge "windcharger: add partition failover to uboot"
diff --git a/board/atheros/board953x/extra.c b/board/atheros/board953x/extra.c
index 71e7f06..841b15e 100755
--- a/board/atheros/board953x/extra.c
+++ b/board/atheros/board953x/extra.c
@@ -28,6 +28,51 @@
 #include <version.h>
 #include <atheros.h>
 
+static int atoi(const char *nptr)
+{
+	int val = 0;
+	while (*nptr >= '0' && *nptr <= '9') {
+		val *= 10;
+		val += *nptr-'0';
+		nptr++;
+	}
+	return val;
+}
+
+static void __do_failover(void)
+{
+	const char *newp;
+	const char *curp = getenv("ACTIVATED_KERNEL_NAME");
+	if (curp && strncmp(curp, "kernel1", strlen("kernel1")) == 0) {
+		newp = "kernel0";
+	} else {
+		newp = "kernel1";
+	}
+	setenv("ACTIVATED_KERNEL_NAME", newp);
+	printf("*** Warning *** failover: switched to %s\n", newp);
+}
+
+void ath_check_failover(void)
+{
+	uint32_t sticky_reg = ath_reg_rd(SPARE_STKY_ADDRESS);
+	const char *threshold_str = getenv("FAILOVER_THRESHOLD");
+	int threshold;
+
+	if (threshold_str) {
+		threshold = atoi(threshold_str);
+	} else {
+		threshold = 3;
+	}
+
+	printf("failover counter: %lu\n", sticky_reg);
+	sticky_reg++;
+	if (sticky_reg > threshold) {
+		__do_failover();
+		sticky_reg = 0;
+	}
+	ath_reg_wr(SPARE_STKY_ADDRESS, sticky_reg);
+}
+
 void ath_set_tuning_caps(void)
 {
 	typedef struct {
diff --git a/common/cmd_sysvar.c b/common/cmd_sysvar.c
index b377b20..5d71077 100644
--- a/common/cmd_sysvar.c
+++ b/common/cmd_sysvar.c
@@ -29,6 +29,10 @@
     .sysvar_name = MAC_ADDR1_SV,
     .uboot_name = MAC_ADDR1_UB,
   },
+  {
+    .sysvar_name = FAILOVER_THRESHOLD_SV,
+    .uboot_name = FAILOVER_THRESHOLD_UB,
+  },
 };
 
 // Some bit twiddling for erasing the correct sector on Atheros flash.  This
diff --git a/common/main.c b/common/main.c
index 80e16bb..45a4d26 100755
--- a/common/main.c
+++ b/common/main.c
@@ -425,8 +425,6 @@
 
 //	debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
 
-        sysvar_init();
-
 	if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
 # ifdef CONFIG_AUTOBOOT_KEYED
 		int prev = disable_ctrlc(1);	/* disable Control C checking */
diff --git a/include/953x.h b/include/953x.h
index 77d226b..2fa46ec 100755
--- a/include/953x.h
+++ b/include/953x.h
@@ -3039,6 +3039,8 @@
 #define RST_BOOTSTRAP_DDR_SELECT_RESET                               0x0 // 0
 #define RST_BOOTSTRAP_ADDRESS                                        0x180600b0
 
+#define SPARE_STKY_ADDRESS                                           0x180600b8
+
 #define RST_CLKGAT_EN_SPARE_MSB                                      31
 #define RST_CLKGAT_EN_SPARE_LSB                                      12
 #define RST_CLKGAT_EN_SPARE_MASK                                     0xfffff000
diff --git a/include/common.h b/include/common.h
index 9865222..f0c1eac 100755
--- a/include/common.h
+++ b/include/common.h
@@ -218,6 +218,8 @@
 #define ACTIVATED_KERNEL_NAME_UB ACTIVATED_KERNEL_NAME_SV
 #define MAC_ADDR1_SV "MAC_ADDR1"
 #define MAC_ADDR1_UB "ethaddr"
+#define FAILOVER_THRESHOLD_SV "FAILOVER_THRESHOLD"
+#define FAILOVER_THRESHOLD_UB FAILOVER_THRESHOLD_SV
 int sysvar_init(void);
 const char *get_sysvar_shared(const char *var);
 const char *get_uboot_name(const char *sysvar_name);
diff --git a/include/configs/board953x.h b/include/configs/board953x.h
index 1b81b53..96a3712 100755
--- a/include/configs/board953x.h
+++ b/include/configs/board953x.h
@@ -143,6 +143,7 @@
  */
 #define __gen_dualboot_cmd(n, a1, a2, f, ec1, ec2, cc1, cc2, el) \
         #n "=" \
+        "run reset_failover; " \
         __if_booting_to_partition_2 \
             __gen_cmd_nn(n, a2, f, ec2, cc2, el) ";" \
         __else \
@@ -266,8 +267,12 @@
 #	define ATH_K_CMD	gen_dualboot_cmd(lk, ATH_K_ADDR, ATH_K_ADDR_2, ATH_K_FILE)
 #endif
 
+#ifndef ATH_RESET_FAILOVER_CMD
+# define ATH_RESET_FAILOVER_CMD "reset_failover=mw 0x180600b8 0\0"
+#endif
+
 #define CONFIG_EXTRA_ENV_SETTINGS	\
-	"dir=\0" "ACTIVATED_KERNEL_NAME=kernel0\0" "extra_bootargs=debug=1 factory=0 wifical=0\0" ATH_U_CMD ATH_F_CMD ATH_K_CMD
+	"dir=\0" "ACTIVATED_KERNEL_NAME=kernel0\0" "extra_bootargs=debug=1 factory=0 wifical=0\0" ATH_U_CMD ATH_F_CMD ATH_K_CMD ATH_RESET_FAILOVER_CMD
 
 #define	CONFIG_BOOTARGS		"console=ttyS0,115200 root=" ATH_ROOT_DEV " rootfstype=squashfs init=/init " MTDPARTS_DEFAULT
 
diff --git a/lib_mips/board.c b/lib_mips/board.c
index 3ddf12f..4f57a70 100755
--- a/lib_mips/board.c
+++ b/lib_mips/board.c
@@ -53,6 +53,11 @@
 #define ath_set_tuning_caps()	/* nothing */
 #endif
 
+#if defined(CONFIG_MACH_QCA953x)
+void ath_check_failover(void);
+#else
+#define ath_check_failover() /* nothing */
+#endif
 
 extern ulong uboot_end_data;
 extern ulong uboot_end;
@@ -458,7 +463,10 @@
 	ath_nand_init();
 #endif
 
-        ath_set_tuning_caps(); /* Needed here not to mess with Ethernet clocks */
+	ath_set_tuning_caps(); /* Needed here not to mess with Ethernet clocks */
+
+	sysvar_init();
+	ath_check_failover();
 
 	/* main_loop() can return to retry autoboot, if so just run it again. */
 	for (;;) {