stm32_flash: Add UART support

Change-Id: Ia2a5a402a2078a239082eb09884c47ecbd2e36d5
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/util/stm32_flash/Android.mk b/util/stm32_flash/Android.mk
index 79a5165..3063c0c 100644
--- a/util/stm32_flash/Android.mk
+++ b/util/stm32_flash/Android.mk
@@ -25,7 +25,8 @@
         i2c.c \
         spi.c \
         stm32_bl.c \
-        stm32f4_crc.c
+        stm32f4_crc.c \
+        uart.c
 
 LOCAL_CFLAGS := -Wall -Werror -Wextra
 
diff --git a/util/stm32_flash/flash.c b/util/stm32_flash/flash.c
index 3f3ab24..6a1adb8 100644
--- a/util/stm32_flash/flash.c
+++ b/util/stm32_flash/flash.c
@@ -31,6 +31,13 @@
 #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)
 {
@@ -65,8 +72,9 @@
     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:csi";
+    char options[] = "d:e:w:a:t:r:l:g:csiu";
     char *dev = device;
     int opt;
     uint32_t address = 0x08000000;
@@ -77,7 +85,7 @@
     uint8_t type = 0x11;
     ssize_t length = 0;
     uint8_t ret;
-    bool use_spi = true;
+    int use_iface = USE_SPI;
     int fd;
     int gpio;
     FILE *file;
@@ -88,6 +96,7 @@
         printf("Usage: %s\n", argv[0]);
         printf("  -s (use spi. default)\n");
         printf("  -i (use i2c)\n");
+        printf("  -u (use uart)\n");
         printf("  -g <gpio> (reset gpio. default: %d)\n", gpio_nreset);
         printf("  -d <device> (device. default: %s)\n", device);
         printf("  -e <sector> (sector to erase)\n");
@@ -128,10 +137,13 @@
             type = strtol(optarg, NULL, 0);
             break;
         case 's':
-            use_spi = true;
+            use_iface = USE_SPI;
             break;
         case 'i':
-            use_spi = false;
+            use_iface = USE_I2C;
+            break;
+        case 'u':
+            use_iface = USE_UART;
             break;
         case 'g':
             gpio_nreset = strtol(optarg, NULL, 0);
@@ -139,7 +151,10 @@
         }
     }
 
-    fd = open(dev, O_RDWR);
+    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;
@@ -158,11 +173,16 @@
         nanosleep(&ts, NULL);
     }
 
-    if (use_spi) {
+    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;
diff --git a/util/stm32_flash/stm32_bl.c b/util/stm32_flash/stm32_bl.c
index 8be1a80..9f651d3 100644
--- a/util/stm32_flash/stm32_bl.c
+++ b/util/stm32_flash/stm32_bl.c
@@ -104,15 +104,14 @@
 
     handle->write_cmd(handle, handle->cmd_erase);
     ret = handle->read_ack(handle);
-    if (ret == CMD_ACK)
+    if (sector < 0xFFF0 && ret == CMD_ACK) {
         write_cnt(handle, 0x0000);
-    if (ret == CMD_ACK)
         ret = read_ack_loop(handle);
-    if (ret == CMD_ACK)
+    }
+    if (ret == CMD_ACK) {
         write_cnt(handle, sector);
-    if (ret == CMD_ACK)
         ret = read_ack_loop(handle);
-
+    }
     return ret;
 }
 
diff --git a/util/stm32_flash/stm32_bl.h b/util/stm32_flash/stm32_bl.h
index 5e396b7..19b9573 100644
--- a/util/stm32_flash/stm32_bl.h
+++ b/util/stm32_flash/stm32_bl.h
@@ -67,6 +67,7 @@
 #define CMD_WRITE_UNPROTECT_NS		0x74
 #define CMD_BUSY			0x76
 #define CMD_ACK				0x79
+#define CMD_UART_ENABLE			0x7F
 #define CMD_READOUT_PROTECT		0x82
 #define CMD_READOUT_PROTECT_NS		0x83
 #define CMD_READOUT_UNPROTECT		0x92
diff --git a/util/stm32_flash/uart.c b/util/stm32_flash/uart.c
new file mode 100644
index 0000000..4ea0899
--- /dev/null
+++ b/util/stm32_flash/uart.c
@@ -0,0 +1,117 @@
+/*
+ * 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 <stdio.h>
+#include <stdint.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/i2c-dev.h>
+
+#include "stm32_bl.h"
+#include "uart.h"
+
+uint8_t uart_write_data(handle_t *handle, uint8_t *buffer, int length)
+{
+    uart_handle_t *uart_handle = (uart_handle_t *)handle;
+
+    buffer[length] = checksum(handle, buffer, length);
+
+    if (write(uart_handle->fd, buffer, length + 1) == (length + 1))
+        return CMD_ACK;
+    else
+        return CMD_NACK;
+}
+
+uint8_t uart_write_cmd(handle_t *handle, uint8_t cmd)
+{
+    uart_handle_t *uart_handle = (uart_handle_t *)handle;
+    uint8_t buffer[2 * sizeof(uint8_t)] = { cmd, ~cmd };
+    int length = 2 * sizeof(uint8_t);
+
+    if (cmd == CMD_UART_ENABLE)
+        length--;
+
+    if (write(uart_handle->fd, buffer, length) == length)
+        return CMD_ACK;
+    else
+        return CMD_NACK;
+}
+
+uint8_t uart_read_data(handle_t *handle, uint8_t *data, int length)
+{
+    uart_handle_t *uart_handle = (uart_handle_t *)handle;
+
+    if (read(uart_handle->fd, data, length) == length)
+        return CMD_ACK;
+    else
+        return CMD_NACK;
+}
+
+uint8_t uart_read_ack(handle_t *handle)
+{
+    uint8_t buffer;
+
+    if (handle->read_data(handle, &buffer, sizeof(uint8_t)) == CMD_ACK)
+        return buffer;
+    else
+        return CMD_BUSY;
+}
+
+int uart_init(handle_t *handle)
+{
+    uart_handle_t *uart_handle = (uart_handle_t *)handle;
+    struct termios tio;
+    int fl;
+
+    handle->cmd_erase = CMD_ERASE;
+    handle->cmd_read_memory = CMD_READ_MEMORY;
+    handle->cmd_write_memory = CMD_WRITE_MEMORY;
+
+    handle->write_data = uart_write_data;
+    handle->write_cmd = uart_write_cmd;
+    handle->read_data = uart_read_data;
+    handle->read_ack = uart_read_ack;
+
+    /* then switch the fd to blocking */
+    fl = fcntl(uart_handle->fd, F_GETFL, 0);
+    if (fl < 0)
+        return fl;
+    fl = fcntl(uart_handle->fd, F_SETFL,  fl & ~O_NDELAY);
+    if (fl < 0)
+        return fl;
+    if (tcgetattr(uart_handle->fd, &tio))
+        memset(&tio, 0, sizeof(tio));
+
+    tio.c_cflag = CS8 | CLOCAL | CREAD | PARENB;
+    cfsetospeed(&tio, B57600);
+    cfsetispeed(&tio, B57600);
+    tio.c_iflag = 0; /* turn off IGNPAR */
+    tio.c_oflag = 0; /* turn off OPOST */
+    tio.c_lflag = 0; /* turn off CANON, ECHO*, etc */
+    tio.c_cc[VTIME] = 5;
+    tio.c_cc[VMIN] = 0;
+    tcflush(uart_handle->fd, TCIFLUSH);
+    tcsetattr(uart_handle->fd, TCSANOW, &tio);
+
+    /* Init USART */
+    uart_write_cmd(handle, CMD_UART_ENABLE);
+    if (uart_read_ack(handle) == CMD_ACK)
+        return 0;
+
+    return -1;
+}
diff --git a/util/stm32_flash/uart.h b/util/stm32_flash/uart.h
new file mode 100644
index 0000000..f701d36
--- /dev/null
+++ b/util/stm32_flash/uart.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#ifndef _UART_H_
+#define _UART_H_
+
+#include "stm32_bl.h"
+
+typedef struct uart_handle
+{
+    handle_t handle;
+    int fd;
+    uint8_t addr;
+} uart_handle_t;
+
+uint8_t uart_write_data(handle_t *handle, uint8_t *buffer, int length);
+uint8_t uart_write_cmd(handle_t *handle, uint8_t cmd);
+uint8_t uart_read_data(handle_t *handle, uint8_t *data, int length);
+uint8_t uart_read_ack(handle_t *handle);
+int uart_init(handle_t *handle);
+
+#endif /* _UART_H_ */