/* * 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 <stdint.h> #include "stm32_bl.h" /* * checksum a sequence of bytes. * length == 1 invert the byte * length > 1 xor all bytes */ uint8_t checksum(__attribute__((unused)) handle_t *handle, uint8_t *bytes, int length) { int i; uint8_t csum; if (length == 1) { csum = ~bytes[0]; } else if (length > 1) { for (csum=0,i=0; i<length; i++) csum ^= bytes[i]; } else { csum = 0xFF; } return csum; } static uint8_t write_len(handle_t *handle, int len) { uint8_t buffer[sizeof(uint8_t)+1]; buffer[0] = len-1; return handle->write_data(handle, buffer, sizeof(uint8_t)); } static uint8_t write_cnt(handle_t *handle, uint16_t cnt) { uint8_t buffer[sizeof(uint16_t)+1]; buffer[0] = (cnt >> 8) & 0xFF; buffer[1] = (cnt ) & 0xFF; return handle->write_data(handle, buffer, sizeof(uint16_t)); } static uint8_t write_addr(handle_t *handle, uint32_t addr) { uint8_t buffer[sizeof(uint32_t)+1]; buffer[0] = (addr >> 24) & 0xFF; buffer[1] = (addr >> 16) & 0xFF; buffer[2] = (addr >> 8) & 0xFF; buffer[3] = (addr ) & 0xFF; return handle->write_data(handle, buffer, sizeof(uint32_t)); } /* write length followed by the data */ static uint8_t write_len_data(handle_t *handle, int len, uint8_t *data) { uint8_t buffer[sizeof(uint8_t)+256+sizeof(uint8_t)]; int i; buffer[0] = len-1; for (i=0; i<len; i++) buffer[1+i] = data[i]; return handle->write_data(handle, buffer, sizeof(uint8_t)+len); } /* keep checking for ack until we receive a ack or nack */ static uint8_t read_ack_loop(handle_t *handle) { uint8_t ret; do { ret = handle->read_ack(handle); } while (ret != CMD_ACK && ret != CMD_NACK); return ret; } /* erase a single sector */ uint8_t erase_sector(handle_t *handle, uint16_t sector) { uint8_t buffer[sizeof(uint16_t)+sizeof(uint16_t)+1]; uint8_t ret; handle->write_cmd(handle, handle->cmd_erase); ret = handle->read_ack(handle); if (ret != CMD_ACK) return ret; if (sector >= 0xFFF0) { /* special erase */ write_cnt(handle, sector); } else if (handle->no_extra_sync) { /* sector erase without extra sync (UART case) */ buffer[0] = 0; /* MSB num of sectors - 1 */ buffer[1] = 0; /* LSB num of sectors - 1 */ buffer[2] = (sector >> 8) & 0xFF; buffer[3] = (sector ) & 0xFF; handle->write_data(handle, buffer, sizeof(uint16_t)+sizeof(uint16_t)); } else { /* sector erase */ write_cnt(handle, 0x0000); ret = read_ack_loop(handle); if (ret != CMD_ACK) return ret; write_cnt(handle, sector); } return read_ack_loop(handle); } /* read memory - this will chop the request into 256 byte reads */ uint8_t read_memory(handle_t *handle, uint32_t addr, uint32_t length, uint8_t *buffer) { uint8_t ret = CMD_ACK; uint32_t offset = 0; while (ret == CMD_ACK && length > offset) { handle->write_cmd(handle, handle->cmd_read_memory); ret = handle->read_ack(handle); if (ret == CMD_ACK) { write_addr(handle, addr+offset); ret = read_ack_loop(handle); if (ret == CMD_ACK) { if (length-offset >= 256) { write_len(handle, 256); ret = read_ack_loop(handle); if (ret == CMD_ACK) { handle->read_data(handle, &buffer[offset], 256); offset += 256; } } else { write_len(handle, length-offset); ret = read_ack_loop(handle); if (ret == CMD_ACK) { handle->read_data(handle, &buffer[offset], length - offset); offset = length; } } } } } return ret; } /* write memory - this will chop the request into 256 byte writes */ uint8_t write_memory(handle_t *handle, uint32_t addr, uint32_t length, uint8_t *buffer) { uint8_t ret = CMD_ACK; uint32_t offset = 0; while (ret == CMD_ACK && length > offset) { handle->write_cmd(handle, handle->cmd_write_memory); ret = handle->read_ack(handle); if (ret == CMD_ACK) { write_addr(handle, addr+offset); ret = read_ack_loop(handle); if (ret == CMD_ACK) { if (length-offset >= 256) { write_len_data(handle, 256, &buffer[offset]); offset += 256; } else { write_len_data(handle, length-offset, &buffer[offset]); offset = length; } ret = read_ack_loop(handle); } } } return ret; }