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 
36 enum USE_INTERFACE {
37     USE_SPI,
38     USE_I2C,
39     USE_UART,
40 };
41 
pad(ssize_t length)42 static inline size_t pad(ssize_t length)
43 {
44     return (length + 3) & ~3;
45 }
46 
tot_len(ssize_t length)47 static 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 
write_byte(int fd,uint8_t byte)53 ssize_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 
main(int argc,char * argv[])64 int 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