Home | History | Annotate | Download | only in stm32_flash
      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 
     42 static inline size_t pad(ssize_t length)
     43 {
     44     return (length + 3) & ~3;
     45 }
     46 
     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 
     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 
     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