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