blob: 2cd287da1f07b49a7a23a0d7050e6e586656d4f4 [file] [log] [blame]
Brian Silverman3aa0d542014-01-25 17:16:43 -08001#include "cape/bootloader_handoff.h"
2
3#include <string.h>
4
5#include "cape/uart_byte.h"
6#include "cape/uart_common.h"
7#include "cape/crc.h"
8#include "cape/util.h"
Brian Silverman8dc9fd42014-02-10 13:35:43 -08009#include "cape/led.h"
Brian Silverman3aa0d542014-01-25 17:16:43 -080010
11// The protocol is pretty simple. Basically, when the bootloader is started, it
12// expects repeated "packets" of data to write. It starts at MAIN_FLASH_START,
13// erases from MAIN_FLASH_START_SECTOR to MAIN_FLASH_END_SECTOR, and keeps
14// writing until MAIN_FLASH_END (if it gets data).
15//
Brian Silverman04fac622014-01-26 18:32:15 -080016// The bootloader sends a NACK when it is first ready to receive bytes. It then
Brian Silverman3aa0d542014-01-25 17:16:43 -080017// expects DATA_BYTES-sized packets (+ the checksum calculated with the standard
18// CRC algorithm). When it successfully receives one and writes it out, it sends
19// ACK. If it has any errors, it waits until there's a 1-second gap (or it
20// receives all the bytes and sees a checksum error) and then sends a NACK.
21
22#define DATA_BYTES 256
23
24#define ACK 0x79
25#define NACK 0x1F
Brian Silverman3aa0d542014-01-25 17:16:43 -080026
27static void process_buffer(uint32_t *buffer) {
28 static uint32_t *out_pointer = (uint32_t *)MAIN_FLASH_START;
29 if ((out_pointer + DATA_BYTES / 4) >= (uint32_t *)MAIN_FLASH_END) return;
30
31 while (FLASH->SR & FLASH_SR_BSY) {}
32 FLASH->CR |= FLASH_CR_PG;
33 for (int i = 0; i < (DATA_BYTES / 4); ++i) {
34 *(out_pointer++) = buffer[i];
35 }
36 while (FLASH->SR & FLASH_SR_BSY) {}
37 FLASH->CR &= ~FLASH_CR_PG;
38}
39
40__attribute__((noreturn)) void bootloader_start(void) {
Brian Silverman8dc9fd42014-02-10 13:35:43 -080041 led_set(LED_ERR, 1);
42 led_set(LED_DB, 1);
43 led_set(LED_Z, 1);
44 led_set(LED_HB, 0);
45
Brian Silverman3aa0d542014-01-25 17:16:43 -080046 crc_init();
47
48 // Unlock the flash so we can program it.
49 FLASH->KEYR = 0x45670123;
50 FLASH->KEYR = 0xCDEF89AB;
51 while (FLASH->CR & FLASH_CR_LOCK) {}
52
53 FLASH->CR =
54 (FLASH->CR & ~(FLASH_CR_PSIZE_0 | FLASH_CR_PSIZE_1)) | FLASH_CR_PSIZE_1;
55
56 FLASH->CR |= FLASH_CR_SER;
57 for (int i = MAIN_FLASH_START_SECTOR; i <= MAIN_FLASH_END_SECTOR; ++i) {
58 while (FLASH->SR & FLASH_SR_BSY) {}
59 FLASH->CR = (FLASH->CR & ~(FLASH_CR_SNB_0 | FLASH_CR_SNB_1 |
60 FLASH_CR_SNB_2 | FLASH_CR_SNB_3)) |
61 i << 3;
62 FLASH->CR |= FLASH_CR_STRT;
63 while (FLASH->CR & FLASH_SR_BSY) {}
64 }
65 FLASH->CR &= ~FLASH_CR_SER;
66
67 uart_common_configure(115200);
68 uart_byte_configure();
69
70 uint8_t buffer[DATA_BYTES + 4] __attribute__((aligned(4)));
71 // Whether we've already encountered an error in this block or not.
72 int error = 0;
73 int bytes_received = 0;
74
Brian Silverman04fac622014-01-26 18:32:15 -080075 uart_byte_send(NACK);
Brian Silverman3aa0d542014-01-25 17:16:43 -080076
77 while (1) {
78 // Receive with a 1 second timeout.
79 int received = uart_byte_receive(60000, 1000 - 1);
80 if (received < 0) {
81 if (received == -1) {
82 uart_byte_send(NACK);
83 error = 0;
84 bytes_received = 0;
85 } else {
86 error = 1;
87 }
88 } else { // successfully received a byte
Brian Silverman8dc9fd42014-02-10 13:35:43 -080089 led_set(LED_HB, bytes_received & 1);
Brian Silverman3aa0d542014-01-25 17:16:43 -080090 if (error == 0) {
91 buffer[bytes_received++] = (uint8_t)received;
92 if (bytes_received == sizeof(buffer)) {
93 bytes_received = 0;
94 uint32_t checksum;
95 memcpy(&checksum, &buffer[DATA_BYTES], 4);
96 uint32_t *buffer32;
97 uint8_t *buffer8 = buffer;
98 memcpy(&buffer32, &buffer8, 4);
99 if (crc_calculate(buffer32, DATA_BYTES / 4) != checksum) {
100 uart_byte_send(NACK);
101 } else {
102 process_buffer(buffer32);
103 uart_byte_send(ACK);
104 }
105 }
106 }
107 }
108 }
109}