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 */
checksum(handle_t * handle,uint8_t * bytes,int length)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
write_len(handle_t * handle,int len)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
write_cnt(handle_t * handle,uint16_t cnt)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
write_addr(handle_t * handle,uint32_t addr)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 */
write_len_data(handle_t * handle,int len,uint8_t * 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 */
read_ack_loop(handle_t * handle)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 */
erase_sector(handle_t * handle,uint16_t sector)101 uint8_t erase_sector(handle_t *handle, uint16_t sector)
102 {
103 uint8_t ret;
104
105 handle->write_cmd(handle, handle->cmd_erase);
106 ret = handle->read_ack(handle);
107 if (ret == CMD_ACK)
108 write_cnt(handle, 0x0000);
109 if (ret == CMD_ACK)
110 ret = read_ack_loop(handle);
111 if (ret == CMD_ACK)
112 write_cnt(handle, sector);
113 if (ret == CMD_ACK)
114 ret = read_ack_loop(handle);
115
116 return ret;
117 }
118
119 /* read memory - this will chop the request into 256 byte reads */
read_memory(handle_t * handle,uint32_t addr,uint32_t length,uint8_t * buffer)120 uint8_t read_memory(handle_t *handle, uint32_t addr, uint32_t length, uint8_t *buffer)
121 {
122 uint8_t ret = CMD_ACK;
123 uint32_t offset = 0;
124
125 while (ret == CMD_ACK && length > offset) {
126 handle->write_cmd(handle, handle->cmd_read_memory);
127 ret = handle->read_ack(handle);
128 if (ret == CMD_ACK) {
129 write_addr(handle, addr+offset);
130 ret = read_ack_loop(handle);
131 if (ret == CMD_ACK) {
132 if (length-offset >= 256) {
133 write_len(handle, 256);
134 ret = read_ack_loop(handle);
135 if (ret == CMD_ACK) {
136 handle->read_data(handle, &buffer[offset], 256);
137 offset += 256;
138 }
139 } else {
140 write_len(handle, length-offset);
141 ret = read_ack_loop(handle);
142 if (ret == CMD_ACK) {
143 handle->read_data(handle, &buffer[offset], length - offset);
144 offset = length;
145 }
146 }
147 }
148 }
149 }
150
151 return ret;
152 }
153
154 /* write memory - this will chop the request into 256 byte writes */
write_memory(handle_t * handle,uint32_t addr,uint32_t length,uint8_t * buffer)155 uint8_t write_memory(handle_t *handle, uint32_t addr, uint32_t length, uint8_t *buffer)
156 {
157 uint8_t ret = CMD_ACK;
158 uint32_t offset = 0;
159
160 while (ret == CMD_ACK && length > offset) {
161 handle->write_cmd(handle, handle->cmd_write_memory);
162 ret = handle->read_ack(handle);
163 if (ret == CMD_ACK) {
164 write_addr(handle, addr+offset);
165 ret = read_ack_loop(handle);
166 if (ret == CMD_ACK) {
167 if (length-offset >= 256) {
168 write_len_data(handle, 256, &buffer[offset]);
169 offset += 256;
170 } else {
171 write_len_data(handle, length-offset, &buffer[offset]);
172 offset = length;
173 }
174 ret = read_ack_loop(handle);
175 }
176 }
177 }
178
179 return ret;
180 }
181