summaryrefslogtreecommitdiff
path: root/software/double_tap_dontboot
diff options
context:
space:
mode:
authorMegan Wachs <megan@sifive.com>2017-01-11 14:36:30 -0800
committerGitHub <noreply@github.com>2017-01-11 14:36:30 -0800
commit3d19e53e38d0e3f3785f159dd08668ab50e11e5a (patch)
treeb65372a7a157ae0ce68c8740754ba9e33be53478 /software/double_tap_dontboot
parent57983086991b12a0c8caf707e5f0b810c3a49647 (diff)
parentc7f7bec992d3d6787cf001892a24d0660ce192b1 (diff)
Merge pull request #45 from sifive/double_tap_dontboot
Add the 'bootloader' which ships on HiFive1 Boards.
Diffstat (limited to 'software/double_tap_dontboot')
-rw-r--r--software/double_tap_dontboot/Makefile6
-rw-r--r--software/double_tap_dontboot/double_tap_dontboot.c148
2 files changed, 154 insertions, 0 deletions
diff --git a/software/double_tap_dontboot/Makefile b/software/double_tap_dontboot/Makefile
new file mode 100644
index 0000000..ae89c51
--- /dev/null
+++ b/software/double_tap_dontboot/Makefile
@@ -0,0 +1,6 @@
+TARGET = double_tap_dontboot
+C_SRCS += double_tap_dontboot.c
+CFLAGS += -O2 -fno-builtin-printf -DNO_INIT
+
+BSP_BASE = ../../bsp
+include $(BSP_BASE)/env/common.mk
diff --git a/software/double_tap_dontboot/double_tap_dontboot.c b/software/double_tap_dontboot/double_tap_dontboot.c
new file mode 100644
index 0000000..0cae5b5
--- /dev/null
+++ b/software/double_tap_dontboot/double_tap_dontboot.c
@@ -0,0 +1,148 @@
+// See LICENSE for license details.
+
+// This is the 'bootloader' which ships on HiFive1 boards,
+// at SPI Flash location 0x20000000.
+// HiFive1 boards have code burned into their OTP which ends with
+// a jump to 0x20000000. The Freedom E SDK and the Arduino IDE
+// linker scripts cause user programs to be compiled and
+// flashed at 0x20400000. Therefore, this code ultimately jumps
+// to 0x20400000, while attempting to leave the machine state as close
+// to its reset state as possible.
+//
+// When compiled in the freedom-e-sdk environment, this code will
+// be compiled as a user program at 0x20400000, so will continuously jump to itself.
+// It is provided in the freedom-e-sdk mostly for reference purposes, so
+// users know what is running on their board. Replacing the bootloader
+// at 0x20000000 is not currently supported by the SDK.
+//
+// These are the instructions for the user of this program, from the
+// HiFive1 Getting Started Guide:
+//
+// This program is designed to allow quick boot, but
+// also a "safe" reboot option if a "bad" program
+// is flashed into the HiFive1's SPI Flash. A "bad" program
+// is one which makes it impossible for the programmer
+// to communicate with the HiFive1. For example, a program which
+// disables FE310's active clock, or which puts the FE310 to sleep
+// with no way of waking it up. Bad programs can always be restarted using
+// the RESET button, and using the "safe" bootloader can be halted
+// before they perform any unsafe behavior.
+//
+// To activate "normal" boot mode, press the RESET button on
+// the HiFive1. After approximately 1s, the green LED will flash
+// for 1/2 second, then the user program will execute.
+//
+// To activate "safe" boot mode, press the RESET button. When
+// the green LED flashes, immediately press the RESET button again.
+// After 1 second, the red LED will blink. The user program will not
+// execute, and the programmer can connect. To exit "safe" boot mode,
+// press the RESET button a final time.
+
+#include <stdint.h>
+#include "platform.h"
+#include "encoding.h"
+
+#define BACKUP15_MAGIC 0xD027B007
+
+#define FINAL_ADDRESS 0x20400000
+
+#define RED_LED 22
+#define GREEN_LED 19
+
+int main(void)
+{
+ uint64_t now;
+ uint64_t then;
+
+ // Restore the default mtvec (which may have been set by initialization
+ // code, depending on the environment in which this C code is compiled).
+ // By default, this would cause an infinite loop upon exception, which is
+ // also "safe" behavior and the debugger can connect.
+
+ write_csr(mtvec, 0x0);
+
+ // How did we get here? We only want to execute this code
+ // on resets (vs waking up from sleep).
+ if ((AON_REG(AON_PMUCAUSE) & AON_PMUCAUSE_WAKEUPCAUSE) ==
+ AON_WAKEUPCAUSE_RESET) {
+
+ if (AON_REG(AON_BACKUP15) == BACKUP15_MAGIC) {
+ // Reset was "double-tapped".
+
+ // Re-arm the reset double-tap
+ AON_REG(AON_BACKUP15) = 0;
+
+ // PWM Red LED
+
+ GPIO_REG(GPIO_IOF_EN) |= (1 << RED_LED);
+ GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << RED_LED);
+ GPIO_REG(GPIO_IOF_SEL) |= (1 << RED_LED);
+
+ GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << GREEN_LED);
+ GPIO_REG(GPIO_OUTPUT_XOR) &= ~(1 << GREEN_LED);
+ GPIO_REG(GPIO_OUTPUT_EN) &= ~(1 << GREEN_LED);
+
+ PWM1_REG(PWM_CFG) = 0;
+ PWM1_REG(PWM_COUNT) = 0;
+ PWM1_REG(PWM_CMP0) = 0xFF;
+ PWM1_REG(PWM_CMP3) = 0xFF;
+ PWM1_REG(PWM_CFG) = PWM_CFG_ENALWAYS;
+
+ int pwm_val = 255;
+
+ // Wait for debugger or another RESET press.
+ while(1){
+
+ // Make the PWM a fade. This is preferable to just a PWM blink
+ // because it makes it clear that the processor is actually
+ // running this code, not just the PWM hardware.
+
+ now = *((volatile uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME));
+ then = now + 32768/500;
+ while (*((volatile uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME)) < then) {
+ asm volatile ("");
+ }
+ pwm_val = (pwm_val == 0) ? 255 : (pwm_val -1);
+ PWM1_REG(PWM_CMP3) = pwm_val << 4;
+ }
+
+ } // If Magic
+
+ // Turn on Green LED to indicate time-to-double-tap
+ // LEDs are Active-Low
+ GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << GREEN_LED);
+ GPIO_REG(GPIO_OUTPUT_XOR) |= (1 << GREEN_LED);
+ GPIO_REG(GPIO_OUTPUT_EN) |= (1 << GREEN_LED);
+
+ // Re-arm the reset double-tap
+ uint32_t save = AON_REG(AON_BACKUP15);
+
+ AON_REG(AON_BACKUP15) = BACKUP15_MAGIC;
+
+ // Wait 500 ms. If reset is tapped at this point,
+ // we will execute the "magic" loop above.
+ now = *((volatile uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME));
+ then = now + 32768/2;
+ while (*((volatile uint64_t*) (CLINT_BASE_ADDR + CLINT_MTIME)) < then) {
+ asm volatile ("");
+ }
+
+ // Re-arm the reset double-tap
+ AON_REG(AON_BACKUP15) = save;
+
+ }
+
+ // Restore the GPIO Registers to their default
+ GPIO_REG(GPIO_OUTPUT_VAL) = 0;
+ GPIO_REG(GPIO_OUTPUT_XOR) = 0;
+ GPIO_REG(GPIO_OUTPUT_EN) = 0;
+
+ // Jump to "user code" in SPI Flash.
+ void (*pgm_start)(void) = (void*) FINAL_ADDRESS;
+ pgm_start();
+
+ // This value is meaningless, but
+ // since this code should never be reached,
+ // make it non-zero.
+ return (1234567);
+}