Add firmware for the ATUSB IEEE 802.15.4 USB Adapter
[linux-libre-firmware.git] / atusb / flash.c
diff --git a/atusb/flash.c b/atusb/flash.c
new file mode 100644 (file)
index 0000000..1f8e59d
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * fw/flash.c - Board-specific flash functions
+ *
+ * Written 2011, 2013-2015 by Werner Almesberger
+ * Copyright 2011, 2013-2015 Werner Almesberger
+ *
+ * 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.
+ */
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <avr/boot.h>
+#include <avr/pgmspace.h>
+
+#include "dfu.h"
+#include "board.h"
+
+
+static uint32_t payload;
+
+
+static void flash_start(void)
+{
+       payload = 0;
+}
+
+
+static bool flash_can_write(uint16_t size)
+{
+       return payload+size <= BOOT_ADDR;
+}
+
+
+static void flash_write(const uint8_t *buf, uint16_t size)
+{
+       static uint8_t last;
+       const uint8_t *p;
+
+       for (p = buf; p != buf+size; p++) {
+               if (!(payload & (SPM_PAGESIZE-1))) {
+                       boot_page_erase(payload);
+                       boot_spm_busy_wait();
+               }
+
+               if (payload & 1)
+                       boot_page_fill(payload, last | (*p << 8));
+               else
+                       last = *p;
+               payload++;
+
+               if (!(payload & (SPM_PAGESIZE-1))) {
+                       boot_page_write(payload-SPM_PAGESIZE);
+                       boot_spm_busy_wait();
+               }
+       }
+}
+
+
+static void flash_end_write(void)
+{
+       if (payload & (SPM_PAGESIZE-1)) {
+               boot_page_write(payload & ~(SPM_PAGESIZE-1));
+               boot_spm_busy_wait();
+       }
+       boot_rww_enable();
+}
+
+
+static uint16_t flash_read(uint8_t *buf, uint16_t size)
+{
+       uint16_t got = 0;
+
+       while (size && payload != (uint32_t) FLASHEND+1) {
+               *buf++ = pgm_read_byte(payload);
+               payload++;
+               size--;
+               got++;
+       }
+       return got;
+}
+
+
+static const struct dfu_flash_ops flash_ops = {
+       .start          = flash_start,
+       .can_write      = flash_can_write,
+       .write          = flash_write,
+       .end_write      = flash_end_write,
+       .read           = flash_read,
+};
+
+
+const struct dfu_flash_ops *dfu_flash_ops = &flash_ops;