1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <unistd.h>
21#include <stdint.h>
22#include <fcntl.h>
23#include <malloc.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <stdbool.h>
27#include <time.h>
28#include <errno.h>
29
30#include "stm32_bl.h"
31#include "stm32f4_crc.h"
32#include "i2c.h"
33#include "spi.h"
34#include "uart.h"
35
36enum USE_INTERFACE {
37    USE_SPI,
38    USE_I2C,
39    USE_UART,
40};
41
42static inline size_t pad(ssize_t length)
43{
44    return (length + 3) & ~3;
45}
46
47static inline size_t tot_len(ssize_t length)
48{
49    // [TYPE:1] [LENGTH:3] [DATA] [PAD:0-3] [CRC:4]
50    return sizeof(uint32_t) + pad(length) + sizeof(uint32_t);
51}
52
53ssize_t write_byte(int fd, uint8_t byte)
54{
55    ssize_t ret;
56
57    do {
58        ret = write(fd, &byte, 1);
59    } while (ret == 0 || (ret == -1 && errno == EINTR));
60
61    return ret;
62}
63
64int main(int argc, char *argv[])
65{
66    uint8_t addr = 0x39;
67    char device[] = "/dev/spidev7.0";
68    int gpio_nreset = 59;
69    char gpio_dev[30];
70    struct stat buf;
71    uint8_t *buffer;
72    uint32_t crc;
73    i2c_handle_t i2c_handle;
74    spi_handle_t spi_handle;
75    uart_handle_t uart_handle;
76    handle_t *handle;
77    char options[] = "d:e:w:a:t:r:l:g:csiu";
78    char *dev = device;
79    int opt;
80    uint32_t address = 0x08000000;
81    char *write_filename = NULL;
82    char *read_filename = NULL;
83    int sector = -1;
84    int do_crc = 0;
85    uint8_t type = 0x11;
86    ssize_t length = 0;
87    uint8_t ret;
88    int use_iface = USE_SPI;
89    int fd;
90    int gpio;
91    FILE *file;
92    int val;
93    struct timespec ts;
94
95    if (argc == 1) {
96        printf("Usage: %s\n", argv[0]);
97        printf("  -s (use spi. default)\n");
98        printf("  -i (use i2c)\n");
99        printf("  -u (use uart)\n");
100        printf("  -g <gpio> (reset gpio. default: %d)\n", gpio_nreset);
101        printf("  -d <device> (device. default: %s)\n", device);
102        printf("  -e <sector> (sector to erase)\n");
103        printf("  -w <filename> (filename to write to flash)\n");
104        printf("  -r <filename> (filename to read from flash)\n");
105        printf("  -l <length> (length to read/write)\n");
106        printf("  -a <address> (address to write filename to. default: 0x%08x)\n",
107               address);
108        printf("  -c (add type, length, file contents, and CRC)\n");
109        printf("  -t <type> (type value for -c option. default: %d)\n", type);
110        return 0;
111    }
112
113    while ((opt = getopt(argc, argv, options)) != -1) {
114        switch (opt) {
115        case 'd':
116            dev = optarg;
117            break;
118        case 'e':
119            sector = strtol(optarg, NULL, 0);
120            break;
121        case 'w':
122            write_filename = optarg;
123            break;
124        case 'r':
125            read_filename = optarg;
126            break;
127        case 'l':
128            length = strtol(optarg, NULL, 0);
129            break;
130        case 'a':
131            address = strtol(optarg, NULL, 0);
132            break;
133        case 'c':
134            do_crc = 1;
135            break;
136        case 't':
137            type = strtol(optarg, NULL, 0);
138            break;
139        case 's':
140            use_iface = USE_SPI;
141            break;
142        case 'i':
143            use_iface = USE_I2C;
144            break;
145        case 'u':
146            use_iface = USE_UART;
147            break;
148        case 'g':
149            gpio_nreset = strtol(optarg, NULL, 0);
150            break;
151        }
152    }
153
154    if (use_iface == USE_UART)
155        fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
156    else
157        fd = open(dev, O_RDWR);
158    if (fd < 0) {
159        perror("Error opening dev");
160        return -1;
161    }
162
163    snprintf(gpio_dev, sizeof(gpio_dev), "/sys/class/gpio/gpio%d/value", gpio_nreset);
164    gpio = open(gpio_dev, O_WRONLY);
165    if (gpio < 0) {
166        perror("Error opening nreset gpio");
167    } else {
168        if (write_byte(gpio, '1') < 0)
169            perror("Failed to set gpio to 1");
170        close(gpio);
171        ts.tv_sec = 0;
172        ts.tv_nsec = 200000000;
173        nanosleep(&ts, NULL);
174    }
175
176    if (use_iface == USE_SPI) {
177        handle = &spi_handle.handle;
178        spi_handle.fd = fd;
179
180        val = spi_init(handle);
181    } else if (use_iface == USE_UART) {
182        handle = &uart_handle.handle;
183        uart_handle.fd = fd;
184
185        val = uart_init(handle);
186    } else {
187        handle = &i2c_handle.handle;
188        i2c_handle.fd = fd;
189        i2c_handle.addr = addr;
190
191        val = i2c_init(handle);
192    }
193
194    if (val < 0) {
195        printf("Init failed\n");
196        return val;
197    }
198
199    if (sector >= 0) {
200        printf("Erasing sector %d\n", sector);
201        ret = erase_sector(handle, sector);
202        if (ret == CMD_ACK)
203            printf("Erase succeeded\n");
204        else
205            printf("Erase failed\n");
206    }
207
208    if (write_filename != NULL) {
209        file = fopen(write_filename, "r");
210        if (!file) {
211            perror("Error opening input file");
212            return -1;
213        }
214
215        if (fstat(fileno(file), &buf) < 0) {
216            perror("error stating file");
217            return -1;
218        }
219
220        /*
221         * For CRC: (when writing to eedata/shared)
222         *   [TYPE:1] [LENGTH:3] [DATA] [PAD:0-3] [CRC:4]
223         * Otherwise:
224         *   [DATA]
225         */
226        buffer = calloc(tot_len(buf.st_size), 1);
227        if (length == 0 || length > buf.st_size)
228            length = buf.st_size;
229
230        if (fread(&buffer[sizeof(uint32_t)], 1, length, file) < (size_t)length) {
231            perror("Error reading input file");
232            free(buffer);
233            fclose(file);
234            return -1;
235        }
236
237        printf("Writing %zd bytes from %s to 0x%08x\n", length,
238               write_filename, address);
239
240        if (do_crc) {
241            /* Populate TYPE, LENGTH, and CRC */
242            buffer[0] = type;
243            buffer[1] = (length >> 16) & 0xFF;
244            buffer[2] = (length >>  8) & 0xFF;
245            buffer[3] = (length      ) & 0xFF;
246            crc = ~stm32f4_crc32(buffer, sizeof(uint32_t) + length);
247
248            memcpy(&buffer[sizeof(uint32_t) + pad(length)],
249                   &crc, sizeof(uint32_t));
250
251            ret = write_memory(handle, address,
252                               tot_len(length), buffer);
253        } else {
254            /* Skip over space reserved for TYPE and LENGTH */
255            ret = write_memory(handle, address,
256                               length, &buffer[sizeof(uint32_t)]);
257        }
258
259        if (ret == CMD_ACK)
260            printf("Write succeeded\n");
261        else
262            printf("Write failed\n");
263
264        free(buffer);
265        fclose(file);
266    }
267
268    if (read_filename != NULL) {
269        file = fopen(read_filename, "w");
270        if (!file) {
271            perror("Error opening output file");
272            return -1;
273        }
274
275        if (length > 0) {
276            /* If passed in a length, just read that many bytes */
277            buffer = calloc(length, 1);
278
279            ret = read_memory(handle, address, length, buffer);
280            if (ret == CMD_ACK) {
281                if (fwrite(buffer, 1, length, file) < (size_t)length)
282                    perror("Failed to write all read bytes to file");
283
284                printf("Read %zd bytes from %s @ 0x%08x\n",
285                       length, read_filename, address);
286            } else {
287                printf("Read failed\n");
288            }
289            free(buffer);
290        } else if (do_crc) {
291            /* otherwise if crc specified, read type, length, data, and crc */
292            uint8_t tmp_buf[sizeof(uint32_t)];
293            ret = read_memory(handle, address, sizeof(uint32_t), tmp_buf);
294            if (ret == CMD_ACK) {
295                type = tmp_buf[0];
296                length = ((tmp_buf[1] << 16) & 0x00FF0000) |
297                         ((tmp_buf[2] <<  8) & 0x0000FF00) |
298                         ((tmp_buf[3]      ) & 0x000000FF);
299
300                if (type != 0xFF) {
301                    buffer = calloc(tot_len(length), 1);
302                    ret = read_memory(handle, address,
303                                      tot_len(length), buffer);
304                    if (ret == CMD_ACK) {
305                        crc = stm32f4_crc32(buffer, tot_len(length));
306                        if (fwrite(buffer, 1, tot_len(length), file) < tot_len(length))
307                            perror("Failed to write all read bytes to file");
308
309                        printf("Read %zd bytes from %s @ 0x%08x (type %02x, crc %s)\n",
310                               length, read_filename, address, type,
311                               crc == STM32F4_CRC_RESIDUE ? "good" : "bad");
312                    } else {
313                        printf("Read of payload failed\n");
314                    }
315                    free(buffer);
316                } else {
317                    printf("Read invalid type: 0xFF\n");
318                }
319            } else {
320                printf("Read of header failed\n");
321            }
322        } else {
323            printf("No length or crc specified for read\n");
324        }
325        fclose(file);
326    }
327
328    gpio = open(gpio_dev, O_WRONLY);
329    if (gpio < 0) {
330        perror("Error opening nreset gpio");
331    } else {
332        if (write_byte(gpio, '0') < 0)
333            perror("Failed to set gpio to 0");
334        close(gpio);
335    }
336
337    close(fd);
338
339    return 0;
340}
341