Add a hard reboot command for gfhd254.

Change-Id: Ie2ef11cd321109a85fb7489183b2a5dc583d5d17
diff --git a/cmds/Makefile b/cmds/Makefile
index 4f7db2b..24bc8a1 100644
--- a/cmds/Makefile
+++ b/cmds/Makefile
@@ -32,6 +32,7 @@
 	diskbench \
 	dnsck \
 	freemegs \
+	gfhd254_reboot \
 	gstatic \
 	http_bouncer \
 	ionice \
diff --git a/cmds/gfhd254_reboot.c b/cmds/gfhd254_reboot.c
new file mode 100644
index 0000000..fdc7e32
--- /dev/null
+++ b/cmds/gfhd254_reboot.c
@@ -0,0 +1,65 @@
+// GFHD254 has a bug where software reset doesn't reset the entire
+// chip, some state in the SAGE engine isn't getting reset.  This
+// drives a gpio that connects back to the chips own external reset
+// pin, resetting the chip with this pin works around the issue as
+// the SAGE engine is completely reset in this path.
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define REG_BASE 0xf0410000
+#define REG_SIZE 0x8000
+
+
+#define GPIO_DATA (0x7404 / 4)
+#define GPIO_IODIR (0x7408 / 4)
+#define CTRL_MUX_0 (0x0700 / 4)
+#define CTRL_MUX_1 (0x0704 / 4)
+
+static void *mmap_(
+    void* addr, size_t size, int prot, int flags, int fd,
+    off_t offset) {
+#ifdef __ANDROID__
+  return mmap64(addr, size, prot, flags, fd,
+                (off64_t)(uint64_t)(uint32_t)offset);
+#else
+  return mmap(addr, size, prot, flags, fd, offset);
+#endif
+}
+
+// TODO(jnewlin):  Revist this after the exact gpio being used
+// is settled on.
+
+int main() {
+  int fd = open("/dev/mem", O_RDWR);
+  volatile uint32_t* reg;
+
+  if (fd < 0) {
+    perror("mmap");
+    return 1;
+  }
+
+  reg = mmap_(NULL, REG_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+              fd, REG_BASE);
+  if (reg == MAP_FAILED) {
+    perror("mmap");
+    return 1;
+  }
+
+  // Set the pin mux to gpio, value of zero selects gpio mode, this
+  // is the reset value so this is probably not required, but just
+  // in case.
+  reg[CTRL_MUX_0] &= ~((0xf << 8) | (0xf << 12)); // aon_gio2 and 3
+  reg[CTRL_MUX_1] &= ~(0xf << 4); // aon_gio9
+
+
+  // Set the direction to be an output and drive it low.
+  reg[GPIO_IODIR] &= ~((1 << 2) | (1 << 3) | (1 << 9));
+  reg[GPIO_DATA] &= ~((1 << 2) | (1 << 3) | (1 << 9));
+
+  return 0;
+}