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 
pad(ssize_t length)35 static inline size_t pad(ssize_t length)
36 {
37     return (length + 3) & ~3;
38 }
39 
tot_len(ssize_t length)40 static inline size_t tot_len(ssize_t length)
41 {
42     // [TYPE:1] [LENGTH:3] [DATA] [PAD:0-3] [CRC:4]
43     return sizeof(uint32_t) + pad(length) + sizeof(uint32_t);
44 }
45 
write_byte(int fd,uint8_t byte)46 ssize_t write_byte(int fd, uint8_t byte)
47 {
48     ssize_t ret;
49 
50     do {
51         ret = write(fd, &byte, 1);
52     } while (ret == 0 || (ret == -1 && errno == EINTR));
53 
54     return ret;
55 }
56 
main(int argc,char * argv[])57 int main(int argc, char *argv[])
58 {
59     uint8_t addr = 0x39;
60     char device[] = "/dev/spidev7.0";
61     int gpio_nreset = 59;
62     char gpio_dev[30];
63     struct stat buf;
64     uint8_t *buffer;
65     uint32_t crc;
66     i2c_handle_t i2c_handle;
67     spi_handle_t spi_handle;
68     handle_t *handle;
69     char options[] = "d:e:w:a:t:r:l:g:csi";
70     char *dev = device;
71     int opt;
72     uint32_t address = 0x08000000;
73     char *write_filename = NULL;
74     char *read_filename = NULL;
75     int sector = -1;
76     int do_crc = 0;
77     uint8_t type = 0x11;
78     ssize_t length = 0;
79     uint8_t ret;
80     bool use_spi = true;
81     int fd;
82     int gpio;
83     FILE *file;
84     int val;
85     struct timespec ts;
86 
87     if (argc == 1) {
88         printf("Usage: %s\n", argv[0]);
89         printf("  -s (use spi. default)\n");
90         printf("  -i (use i2c)\n");
91         printf("  -g <gpio> (reset gpio. default: %d)\n", gpio_nreset);
92         printf("  -d <device> (device. default: %s)\n", device);
93         printf("  -e <sector> (sector to erase)\n");
94         printf("  -w <filename> (filename to write to flash)\n");
95         printf("  -r <filename> (filename to read from flash)\n");
96         printf("  -l <length> (length to read/write)\n");
97         printf("  -a <address> (address to write filename to. default: 0x%08x)\n",
98                address);
99         printf("  -c (add type, length, file contents, and CRC)\n");
100         printf("  -t <type> (type value for -c option. default: %d)\n", type);
101         return 0;
102     }
103 
104     while ((opt = getopt(argc, argv, options)) != -1) {
105         switch (opt) {
106         case 'd':
107             dev = optarg;
108             break;
109         case 'e':
110             sector = strtol(optarg, NULL, 0);
111             break;
112         case 'w':
113             write_filename = optarg;
114             break;
115         case 'r':
116             read_filename = optarg;
117             break;
118         case 'l':
119             length = strtol(optarg, NULL, 0);
120             break;
121         case 'a':
122             address = strtol(optarg, NULL, 0);
123             break;
124         case 'c':
125             do_crc = 1;
126             break;
127         case 't':
128             type = strtol(optarg, NULL, 0);
129             break;
130         case 's':
131             use_spi = true;
132             break;
133         case 'i':
134             use_spi = false;
135             break;
136         case 'g':
137             gpio_nreset = strtol(optarg, NULL, 0);
138             break;
139         }
140     }
141 
142     fd = open(dev, O_RDWR);
143     if (fd < 0) {
144         perror("Error opening dev");
145         return -1;
146     }
147 
148     snprintf(gpio_dev, sizeof(gpio_dev), "/sys/class/gpio/gpio%d/value", gpio_nreset);
149     gpio = open(gpio_dev, O_WRONLY);
150     if (gpio < 0) {
151         perror("Error opening nreset gpio");
152     } else {
153         if (write_byte(gpio, '1') < 0)
154             perror("Failed to set gpio to 1");
155         close(gpio);
156         ts.tv_sec = 0;
157         ts.tv_nsec = 5000000;
158         nanosleep(&ts, NULL);
159     }
160 
161     if (use_spi) {
162         handle = &spi_handle.handle;
163         spi_handle.fd = fd;
164 
165         val = spi_init(handle);
166     } else {
167         handle = &i2c_handle.handle;
168         i2c_handle.fd = fd;
169         i2c_handle.addr = addr;
170 
171         val = i2c_init(handle);
172     }
173 
174     if (val < 0)
175         return val;
176 
177     if (sector >= 0) {
178         printf("Erasing sector %d\n", sector);
179         ret = erase_sector(handle, sector);
180         if (ret == CMD_ACK)
181             printf("Erase succeeded\n");
182         else
183             printf("Erase failed\n");
184     }
185 
186     if (write_filename != NULL) {
187         file = fopen(write_filename, "r");
188         if (!file) {
189             perror("Error opening input file");
190             return -1;
191         }
192 
193         if (fstat(fileno(file), &buf) < 0) {
194             perror("error stating file");
195             return -1;
196         }
197 
198         /*
199          * For CRC: (when writing to eedata/shared)
200          *   [TYPE:1] [LENGTH:3] [DATA] [PAD:0-3] [CRC:4]
201          * Otherwise:
202          *   [DATA]
203          */
204         buffer = calloc(tot_len(buf.st_size), 1);
205         if (length == 0 || length > buf.st_size)
206             length = buf.st_size;
207 
208         if (fread(&buffer[sizeof(uint32_t)], 1, length, file) < (size_t)length) {
209             perror("Error reading input file");
210             return -1;
211         }
212 
213         printf("Writing %zd bytes from %s to 0x%08x\n", length,
214                write_filename, address);
215 
216         if (do_crc) {
217             /* Populate TYPE, LENGTH, and CRC */
218             buffer[0] = type;
219             buffer[1] = (length >> 16) & 0xFF;
220             buffer[2] = (length >>  8) & 0xFF;
221             buffer[3] = (length      ) & 0xFF;
222             crc = ~stm32f4_crc32(buffer, sizeof(uint32_t) + length);
223 
224             memcpy(&buffer[sizeof(uint32_t) + pad(length)],
225                    &crc, sizeof(uint32_t));
226 
227             ret = write_memory(handle, address,
228                                tot_len(length), buffer);
229         } else {
230             /* Skip over space reserved for TYPE and LENGTH */
231             ret = write_memory(handle, address,
232                                length, &buffer[sizeof(uint32_t)]);
233         }
234 
235         if (ret == CMD_ACK)
236             printf("Write succeeded\n");
237         else
238             printf("Write failed\n");
239 
240         free(buffer);
241         fclose(file);
242     }
243 
244     if (read_filename != NULL) {
245         file = fopen(read_filename, "w");
246         if (!file) {
247             perror("Error opening output file");
248             return -1;
249         }
250 
251         if (length > 0) {
252             /* If passed in a length, just read that many bytes */
253             buffer = calloc(length, 1);
254 
255             ret = read_memory(handle, address, length, buffer);
256             if (ret == CMD_ACK) {
257                 if (fwrite(buffer, 1, length, file) < (size_t)length)
258                     perror("Failed to write all read bytes to file");
259 
260                 printf("Read %zd bytes from %s @ 0x%08x\n",
261                        length, read_filename, address);
262             } else {
263                 printf("Read failed\n");
264             }
265             free(buffer);
266         } else if (do_crc) {
267             /* otherwise if crc specified, read type, length, data, and crc */
268             uint8_t tmp_buf[sizeof(uint32_t)];
269             ret = read_memory(handle, address, sizeof(uint32_t), tmp_buf);
270             if (ret == CMD_ACK) {
271                 type = tmp_buf[0];
272                 length = ((tmp_buf[1] << 16) & 0x00FF0000) |
273                          ((tmp_buf[2] <<  8) & 0x0000FF00) |
274                          ((tmp_buf[3]      ) & 0x000000FF);
275 
276                 if (type != 0xFF) {
277                     buffer = calloc(tot_len(length), 1);
278                     ret = read_memory(handle, address,
279                                       tot_len(length), buffer);
280                     if (ret == CMD_ACK) {
281                         crc = stm32f4_crc32(buffer, tot_len(length));
282                         if (fwrite(buffer, 1, tot_len(length), file) < tot_len(length))
283                             perror("Failed to write all read bytes to file");
284 
285                         printf("Read %zd bytes from %s @ 0x%08x (type %02x, crc %s)\n",
286                                length, read_filename, address, type,
287                                crc == STM32F4_CRC_RESIDUE ? "good" : "bad");
288                     } else {
289                         printf("Read of payload failed\n");
290                     }
291                     free(buffer);
292                 } else {
293                     printf("Read invalid type: 0xFF\n");
294                 }
295             } else {
296                 printf("Read of header failed\n");
297             }
298         } else {
299             printf("No length or crc specified for read\n");
300         }
301         fclose(file);
302     }
303 
304     gpio = open(gpio_dev, O_WRONLY);
305     if (gpio < 0) {
306         perror("Error opening nreset gpio");
307     } else {
308         if (write_byte(gpio, '0') < 0)
309             perror("Failed to set gpio to 0");
310         close(gpio);
311     }
312 
313     close(fd);
314 
315     return 0;
316 }
317