/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "stm32_bl.h" #include "stm32f4_crc.h" #include "i2c.h" #include "spi.h" #include "uart.h" enum USE_INTERFACE { USE_SPI, USE_I2C, USE_UART, }; static inline size_t pad(ssize_t length) { return (length + 3) & ~3; } static inline size_t tot_len(ssize_t length) { // [TYPE:1] [LENGTH:3] [DATA] [PAD:0-3] [CRC:4] return sizeof(uint32_t) + pad(length) + sizeof(uint32_t); } ssize_t write_byte(int fd, uint8_t byte) { ssize_t ret; do { ret = write(fd, &byte, 1); } while (ret == 0 || (ret == -1 && errno == EINTR)); return ret; } int main(int argc, char *argv[]) { uint8_t addr = 0x39; char device[] = "/dev/spidev7.0"; int gpio_nreset = 59; char gpio_dev[30]; struct stat buf; uint8_t *buffer; uint32_t crc; i2c_handle_t i2c_handle; spi_handle_t spi_handle; uart_handle_t uart_handle; handle_t *handle; char options[] = "d:e:w:a:t:r:l:g:csiu"; char *dev = device; int opt; uint32_t address = 0x08000000; char *write_filename = NULL; char *read_filename = NULL; int sector = -1; int do_crc = 0; uint8_t type = 0x11; ssize_t length = 0; uint8_t ret; int use_iface = USE_SPI; int fd; int gpio; FILE *file; int val; struct timespec ts; if (argc == 1) { printf("Usage: %s\n", argv[0]); printf(" -s (use spi. default)\n"); printf(" -i (use i2c)\n"); printf(" -u (use uart)\n"); printf(" -g (reset gpio. default: %d)\n", gpio_nreset); printf(" -d (device. default: %s)\n", device); printf(" -e (sector to erase)\n"); printf(" -w (filename to write to flash)\n"); printf(" -r (filename to read from flash)\n"); printf(" -l (length to read/write)\n"); printf(" -a
(address to write filename to. default: 0x%08x)\n", address); printf(" -c (add type, length, file contents, and CRC)\n"); printf(" -t (type value for -c option. default: %d)\n", type); return 0; } while ((opt = getopt(argc, argv, options)) != -1) { switch (opt) { case 'd': dev = optarg; break; case 'e': sector = strtol(optarg, NULL, 0); break; case 'w': write_filename = optarg; break; case 'r': read_filename = optarg; break; case 'l': length = strtol(optarg, NULL, 0); break; case 'a': address = strtol(optarg, NULL, 0); break; case 'c': do_crc = 1; break; case 't': type = strtol(optarg, NULL, 0); break; case 's': use_iface = USE_SPI; break; case 'i': use_iface = USE_I2C; break; case 'u': use_iface = USE_UART; break; case 'g': gpio_nreset = strtol(optarg, NULL, 0); break; } } if (use_iface == USE_UART) fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY); else fd = open(dev, O_RDWR); if (fd < 0) { perror("Error opening dev"); return -1; } snprintf(gpio_dev, sizeof(gpio_dev), "/sys/class/gpio/gpio%d/value", gpio_nreset); gpio = open(gpio_dev, O_WRONLY); if (gpio < 0) { perror("Error opening nreset gpio"); } else { if (write_byte(gpio, '1') < 0) perror("Failed to set gpio to 1"); close(gpio); ts.tv_sec = 0; ts.tv_nsec = 200000000; nanosleep(&ts, NULL); } if (use_iface == USE_SPI) { handle = &spi_handle.handle; spi_handle.fd = fd; val = spi_init(handle); } else if (use_iface == USE_UART) { handle = &uart_handle.handle; uart_handle.fd = fd; val = uart_init(handle); } else { handle = &i2c_handle.handle; i2c_handle.fd = fd; i2c_handle.addr = addr; val = i2c_init(handle); } if (val < 0) { printf("Init failed\n"); return val; } if (sector >= 0) { printf("Erasing sector %d\n", sector); ret = erase_sector(handle, sector); if (ret == CMD_ACK) printf("Erase succeeded\n"); else printf("Erase failed\n"); } if (write_filename != NULL) { file = fopen(write_filename, "r"); if (!file) { perror("Error opening input file"); return -1; } if (fstat(fileno(file), &buf) < 0) { perror("error stating file"); return -1; } /* * For CRC: (when writing to eedata/shared) * [TYPE:1] [LENGTH:3] [DATA] [PAD:0-3] [CRC:4] * Otherwise: * [DATA] */ buffer = calloc(tot_len(buf.st_size), 1); if (length == 0 || length > buf.st_size) length = buf.st_size; if (fread(&buffer[sizeof(uint32_t)], 1, length, file) < (size_t)length) { perror("Error reading input file"); free(buffer); fclose(file); return -1; } printf("Writing %zd bytes from %s to 0x%08x\n", length, write_filename, address); if (do_crc) { /* Populate TYPE, LENGTH, and CRC */ buffer[0] = type; buffer[1] = (length >> 16) & 0xFF; buffer[2] = (length >> 8) & 0xFF; buffer[3] = (length ) & 0xFF; crc = ~stm32f4_crc32(buffer, sizeof(uint32_t) + length); memcpy(&buffer[sizeof(uint32_t) + pad(length)], &crc, sizeof(uint32_t)); ret = write_memory(handle, address, tot_len(length), buffer); } else { /* Skip over space reserved for TYPE and LENGTH */ ret = write_memory(handle, address, length, &buffer[sizeof(uint32_t)]); } if (ret == CMD_ACK) printf("Write succeeded\n"); else printf("Write failed\n"); free(buffer); fclose(file); } if (read_filename != NULL) { file = fopen(read_filename, "w"); if (!file) { perror("Error opening output file"); return -1; } if (length > 0) { /* If passed in a length, just read that many bytes */ buffer = calloc(length, 1); ret = read_memory(handle, address, length, buffer); if (ret == CMD_ACK) { if (fwrite(buffer, 1, length, file) < (size_t)length) perror("Failed to write all read bytes to file"); printf("Read %zd bytes from %s @ 0x%08x\n", length, read_filename, address); } else { printf("Read failed\n"); } free(buffer); } else if (do_crc) { /* otherwise if crc specified, read type, length, data, and crc */ uint8_t tmp_buf[sizeof(uint32_t)]; ret = read_memory(handle, address, sizeof(uint32_t), tmp_buf); if (ret == CMD_ACK) { type = tmp_buf[0]; length = ((tmp_buf[1] << 16) & 0x00FF0000) | ((tmp_buf[2] << 8) & 0x0000FF00) | ((tmp_buf[3] ) & 0x000000FF); if (type != 0xFF) { buffer = calloc(tot_len(length), 1); ret = read_memory(handle, address, tot_len(length), buffer); if (ret == CMD_ACK) { crc = stm32f4_crc32(buffer, tot_len(length)); if (fwrite(buffer, 1, tot_len(length), file) < tot_len(length)) perror("Failed to write all read bytes to file"); printf("Read %zd bytes from %s @ 0x%08x (type %02x, crc %s)\n", length, read_filename, address, type, crc == STM32F4_CRC_RESIDUE ? "good" : "bad"); } else { printf("Read of payload failed\n"); } free(buffer); } else { printf("Read invalid type: 0xFF\n"); } } else { printf("Read of header failed\n"); } } else { printf("No length or crc specified for read\n"); } fclose(file); } gpio = open(gpio_dev, O_WRONLY); if (gpio < 0) { perror("Error opening nreset gpio"); } else { if (write_byte(gpio, '0') < 0) perror("Failed to set gpio to 0"); close(gpio); } close(fd); return 0; }