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 <stdint.h>
     18 
     19 #include "stm32_bl.h"
     20 
     21 /*
     22  * checksum a sequence of bytes.
     23  * length == 1 invert the byte
     24  * length > 1 xor all bytes
     25  */
     26 uint8_t checksum(__attribute__((unused)) handle_t *handle, uint8_t *bytes, int length)
     27 {
     28     int i;
     29     uint8_t csum;
     30 
     31     if (length == 1) {
     32         csum = ~bytes[0];
     33     } else if (length > 1) {
     34         for (csum=0,i=0; i<length; i++)
     35             csum ^= bytes[i];
     36     } else {
     37         csum = 0xFF;
     38     }
     39 
     40     return csum;
     41 }
     42 
     43 static uint8_t write_len(handle_t *handle, int len)
     44 {
     45     uint8_t buffer[sizeof(uint8_t)+1];
     46 
     47     buffer[0] = len-1;
     48 
     49     return handle->write_data(handle, buffer, sizeof(uint8_t));
     50 }
     51 
     52 static uint8_t write_cnt(handle_t *handle, uint16_t cnt)
     53 {
     54     uint8_t buffer[sizeof(uint16_t)+1];
     55 
     56     buffer[0] = (cnt >> 8) & 0xFF;
     57     buffer[1] = (cnt     ) & 0xFF;
     58 
     59     return handle->write_data(handle, buffer, sizeof(uint16_t));
     60 }
     61 
     62 static uint8_t write_addr(handle_t *handle, uint32_t addr)
     63 {
     64     uint8_t buffer[sizeof(uint32_t)+1];
     65 
     66     buffer[0] = (addr >> 24) & 0xFF;
     67     buffer[1] = (addr >> 16) & 0xFF;
     68     buffer[2] = (addr >>  8) & 0xFF;
     69     buffer[3] = (addr      ) & 0xFF;
     70 
     71     return handle->write_data(handle, buffer, sizeof(uint32_t));
     72 }
     73 
     74 /* write length followed by the data */
     75 static uint8_t write_len_data(handle_t *handle, int len, uint8_t *data)
     76 {
     77     uint8_t buffer[sizeof(uint8_t)+256+sizeof(uint8_t)];
     78     int i;
     79 
     80     buffer[0] = len-1;
     81 
     82     for (i=0; i<len; i++)
     83         buffer[1+i] = data[i];
     84 
     85     return handle->write_data(handle, buffer, sizeof(uint8_t)+len);
     86 }
     87 
     88 /* keep checking for ack until we receive a ack or nack */
     89 static uint8_t read_ack_loop(handle_t *handle)
     90 {
     91     uint8_t ret;
     92 
     93     do {
     94         ret = handle->read_ack(handle);
     95     } while (ret != CMD_ACK && ret != CMD_NACK);
     96 
     97     return ret;
     98 }
     99 
    100 /* erase a single sector */
    101 uint8_t erase_sector(handle_t *handle, uint16_t sector)
    102 {
    103     uint8_t buffer[sizeof(uint16_t)+sizeof(uint16_t)+1];
    104     uint8_t ret;
    105 
    106     handle->write_cmd(handle, handle->cmd_erase);
    107     ret = handle->read_ack(handle);
    108     if (ret != CMD_ACK)
    109         return ret;
    110 
    111     if (sector >= 0xFFF0) {
    112         /* special erase */
    113         write_cnt(handle, sector);
    114     } else if (handle->no_extra_sync) {
    115         /* sector erase without extra sync (UART case) */
    116         buffer[0] = 0;  /* MSB num of sectors - 1 */
    117         buffer[1] = 0;  /* LSB num of sectors - 1 */
    118         buffer[2] = (sector >> 8) & 0xFF;
    119         buffer[3] = (sector     ) & 0xFF;
    120         handle->write_data(handle, buffer, sizeof(uint16_t)+sizeof(uint16_t));
    121     } else {
    122         /* sector erase */
    123         write_cnt(handle, 0x0000);
    124         ret = read_ack_loop(handle);
    125         if (ret != CMD_ACK)
    126             return ret;
    127         write_cnt(handle, sector);
    128     }
    129 
    130     return read_ack_loop(handle);
    131 }
    132 
    133 /* read memory - this will chop the request into 256 byte reads */
    134 uint8_t read_memory(handle_t *handle, uint32_t addr, uint32_t length, uint8_t *buffer)
    135 {
    136     uint8_t ret = CMD_ACK;
    137     uint32_t offset = 0;
    138 
    139     while (ret == CMD_ACK && length > offset) {
    140         handle->write_cmd(handle, handle->cmd_read_memory);
    141         ret = handle->read_ack(handle);
    142         if (ret == CMD_ACK) {
    143             write_addr(handle, addr+offset);
    144             ret = read_ack_loop(handle);
    145             if (ret == CMD_ACK) {
    146                 if (length-offset >= 256) {
    147                     write_len(handle, 256);
    148                     ret = read_ack_loop(handle);
    149                     if (ret == CMD_ACK) {
    150                         handle->read_data(handle, &buffer[offset], 256);
    151                         offset += 256;
    152                     }
    153                 } else {
    154                     write_len(handle, length-offset);
    155                     ret = read_ack_loop(handle);
    156                     if (ret == CMD_ACK) {
    157                         handle->read_data(handle, &buffer[offset], length - offset);
    158                         offset = length;
    159                     }
    160                 }
    161             }
    162         }
    163     }
    164 
    165     return ret;
    166 }
    167 
    168 /* write memory - this will chop the request into 256 byte writes */
    169 uint8_t write_memory(handle_t *handle, uint32_t addr, uint32_t length, uint8_t *buffer)
    170 {
    171     uint8_t ret = CMD_ACK;
    172     uint32_t offset = 0;
    173 
    174     while (ret == CMD_ACK && length > offset) {
    175         handle->write_cmd(handle, handle->cmd_write_memory);
    176         ret = handle->read_ack(handle);
    177         if (ret == CMD_ACK) {
    178             write_addr(handle, addr+offset);
    179             ret = read_ack_loop(handle);
    180             if (ret == CMD_ACK) {
    181                 if (length-offset >= 256) {
    182                     write_len_data(handle, 256, &buffer[offset]);
    183                     offset += 256;
    184                 } else {
    185                     write_len_data(handle, length-offset, &buffer[offset]);
    186                     offset = length;
    187                 }
    188                 ret = read_ack_loop(handle);
    189             }
    190         }
    191     }
    192 
    193     return ret;
    194 }
    195