195 lines
5.4 KiB
C
195 lines
5.4 KiB
C
/*
|
|
* 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;
|
|
}
|