Add firmware for the ATUSB IEEE 802.15.4 USB Adapter
[linux-libre-firmware.git] / atusb / flash.c
1 /*
2  * fw/flash.c - Board-specific flash functions
3  *
4  * Written 2011, 2013-2015 by Werner Almesberger
5  * Copyright 2011, 2013-2015 Werner Almesberger
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  */
12
13
14 #include <stdbool.h>
15 #include <stdint.h>
16
17 #include <avr/boot.h>
18 #include <avr/pgmspace.h>
19
20 #include "dfu.h"
21 #include "board.h"
22
23
24 static uint32_t payload;
25
26
27 static void flash_start(void)
28 {
29         payload = 0;
30 }
31
32
33 static bool flash_can_write(uint16_t size)
34 {
35         return payload+size <= BOOT_ADDR;
36 }
37
38
39 static void flash_write(const uint8_t *buf, uint16_t size)
40 {
41         static uint8_t last;
42         const uint8_t *p;
43
44         for (p = buf; p != buf+size; p++) {
45                 if (!(payload & (SPM_PAGESIZE-1))) {
46                         boot_page_erase(payload);
47                         boot_spm_busy_wait();
48                 }
49
50                 if (payload & 1)
51                         boot_page_fill(payload, last | (*p << 8));
52                 else
53                         last = *p;
54                 payload++;
55
56                 if (!(payload & (SPM_PAGESIZE-1))) {
57                         boot_page_write(payload-SPM_PAGESIZE);
58                         boot_spm_busy_wait();
59                 }
60         }
61 }
62
63
64 static void flash_end_write(void)
65 {
66         if (payload & (SPM_PAGESIZE-1)) {
67                 boot_page_write(payload & ~(SPM_PAGESIZE-1));
68                 boot_spm_busy_wait();
69         }
70         boot_rww_enable();
71 }
72
73
74 static uint16_t flash_read(uint8_t *buf, uint16_t size)
75 {
76         uint16_t got = 0;
77
78         while (size && payload != (uint32_t) FLASHEND+1) {
79                 *buf++ = pgm_read_byte(payload);
80                 payload++;
81                 size--;
82                 got++;
83         }
84         return got;
85 }
86
87
88 static const struct dfu_flash_ops flash_ops = {
89         .start          = flash_start,
90         .can_write      = flash_can_write,
91         .write          = flash_write,
92         .end_write      = flash_end_write,
93         .read           = flash_read,
94 };
95
96
97 const struct dfu_flash_ops *dfu_flash_ops = &flash_ops;