blob: 2c5a9c9dc3ad1e675759786be5db8d39916181a2 [file] [log] [blame]
David Brown5153bd62017-01-06 11:16:53 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20#include <zephyr.h>
David Brown5153bd62017-01-06 11:16:53 -070021#include <flash.h>
22
Marti Bolivar51181cf2017-03-20 11:03:41 -040023#include "target.h"
Ricardo Salveti3a2c1242017-01-19 10:22:35 -020024
David Brown5153bd62017-01-06 11:16:53 -070025#include <flash_map/flash_map.h>
26#include <hal/hal_flash.h>
27#include <sysflash/sysflash.h>
28
Marti Bolivar4a97b4c2017-01-31 18:20:02 -050029#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_INFO
30#include "bootutil/bootutil_log.h"
Ricardo Salveti7cf3d9e2017-01-18 16:38:22 -020031
David Brown5153bd62017-01-06 11:16:53 -070032extern struct device *boot_flash_device;
33
34/*
Marti Bolivarf6603062017-05-01 17:34:22 -040035 * For now, we only support one flash device.
36 *
37 * Pick a random device ID for it that's unlikely to collide with
38 * anything "real".
39 */
40#define FLASH_DEVICE_ID 100
41#define FLASH_DEVICE_BASE CONFIG_FLASH_BASE_ADDRESS
42
43/*
David Brown5153bd62017-01-06 11:16:53 -070044 * The flash area describes essentially the partition table of the
45 * flash. In this case, it starts with FLASH_AREA_IMAGE_0.
46 */
47static const struct flash_area part_map[] = {
David Brown0d0652a2017-04-11 17:33:30 -060048 {
49 .fa_id = FLASH_AREA_IMAGE_0,
Marti Bolivarf6603062017-05-01 17:34:22 -040050 .fa_device_id = FLASH_DEVICE_ID,
David Brown0d0652a2017-04-11 17:33:30 -060051 .fa_off = FLASH_AREA_IMAGE_0_OFFSET,
52 .fa_size = FLASH_AREA_IMAGE_0_SIZE,
53 },
54 {
55 .fa_id = FLASH_AREA_IMAGE_1,
Marti Bolivarf6603062017-05-01 17:34:22 -040056 .fa_device_id = FLASH_DEVICE_ID,
David Brown0d0652a2017-04-11 17:33:30 -060057 .fa_off = FLASH_AREA_IMAGE_1_OFFSET,
58 .fa_size = FLASH_AREA_IMAGE_1_SIZE,
59 },
60 {
61 .fa_id = FLASH_AREA_IMAGE_SCRATCH,
Marti Bolivarf6603062017-05-01 17:34:22 -040062 .fa_device_id = FLASH_DEVICE_ID,
David Brown0d0652a2017-04-11 17:33:30 -060063 .fa_off = FLASH_AREA_IMAGE_SCRATCH_OFFSET,
64 .fa_size = FLASH_AREA_IMAGE_SCRATCH_SIZE,
65 },
David Brown5153bd62017-01-06 11:16:53 -070066};
67
Marti Bolivarf6603062017-05-01 17:34:22 -040068int flash_device_base(uint8_t fd_id, uintptr_t *ret)
69{
70 if (fd_id != FLASH_DEVICE_ID) {
71 BOOT_LOG_ERR("invalid flash ID %d; expected %d",
72 fd_id, FLASH_DEVICE_ID);
73 return -EINVAL;
74 }
75 *ret = FLASH_DEVICE_BASE;
76 return 0;
77}
78
David Brown5153bd62017-01-06 11:16:53 -070079/*
David Brown5153bd62017-01-06 11:16:53 -070080 * `open` a flash area. The `area` in this case is not the individual
81 * sectors, but describes the particular flash area in question.
82 */
83int flash_area_open(uint8_t id, const struct flash_area **area)
84{
David Brown0d0652a2017-04-11 17:33:30 -060085 int i;
Ricardo Salveti7cf3d9e2017-01-18 16:38:22 -020086
David Brown0d0652a2017-04-11 17:33:30 -060087 BOOT_LOG_DBG("area %d", id);
David Brown5153bd62017-01-06 11:16:53 -070088
David Brown0d0652a2017-04-11 17:33:30 -060089 for (i = 0; i < ARRAY_SIZE(part_map); i++) {
David Brown74b3c582017-04-11 17:39:25 -060090 if (id == part_map[i].fa_id) {
David Brown0d0652a2017-04-11 17:33:30 -060091 break;
David Brown74b3c582017-04-11 17:39:25 -060092 }
David Brown0d0652a2017-04-11 17:33:30 -060093 }
David Brown74b3c582017-04-11 17:39:25 -060094 if (i == ARRAY_SIZE(part_map)) {
David Brown0d0652a2017-04-11 17:33:30 -060095 return -1;
David Brown74b3c582017-04-11 17:39:25 -060096 }
David Brown5153bd62017-01-06 11:16:53 -070097
David Brown0d0652a2017-04-11 17:33:30 -060098 *area = &part_map[i];
99 return 0;
David Brown5153bd62017-01-06 11:16:53 -0700100}
101
102/*
103 * Nothing to do on close.
104 */
105void flash_area_close(const struct flash_area *area)
106{
107}
108
109int flash_area_read(const struct flash_area *area, uint32_t off, void *dst,
David Brown0d0652a2017-04-11 17:33:30 -0600110 uint32_t len)
David Brown5153bd62017-01-06 11:16:53 -0700111{
David Brown0d0652a2017-04-11 17:33:30 -0600112 BOOT_LOG_DBG("area=%d, off=%x, len=%x", area->fa_id, off, len);
113 return flash_read(boot_flash_device, area->fa_off + off, dst, len);
David Brown5153bd62017-01-06 11:16:53 -0700114}
115
116int flash_area_write(const struct flash_area *area, uint32_t off, const void *src,
David Brown0d0652a2017-04-11 17:33:30 -0600117 uint32_t len)
David Brown5153bd62017-01-06 11:16:53 -0700118{
David Brown0d0652a2017-04-11 17:33:30 -0600119 int rc = 0;
Michael Scotte12746c2017-01-31 16:07:08 -0800120
David Brown0d0652a2017-04-11 17:33:30 -0600121 BOOT_LOG_DBG("area=%d, off=%x, len=%x", area->fa_id, off, len);
122 flash_write_protection_set(boot_flash_device, false);
123 rc = flash_write(boot_flash_device, area->fa_off + off, src, len);
124 flash_write_protection_set(boot_flash_device, true);
125 return rc;
David Brown5153bd62017-01-06 11:16:53 -0700126}
127
128int flash_area_erase(const struct flash_area *area, uint32_t off, uint32_t len)
129{
David Brown0d0652a2017-04-11 17:33:30 -0600130 int rc;
Marti Bolivar53cfdb92017-02-10 15:05:22 -0500131
David Brown0d0652a2017-04-11 17:33:30 -0600132 BOOT_LOG_DBG("area=%d, off=%x, len=%x", area->fa_id, off, len);
133 flash_write_protection_set(boot_flash_device, false);
134 rc = flash_erase(boot_flash_device, area->fa_off + off, len);
135 flash_write_protection_set(boot_flash_device, true);
136 return rc;
David Brown5153bd62017-01-06 11:16:53 -0700137}
138
139uint8_t flash_area_align(const struct flash_area *area)
140{
David Brown0d0652a2017-04-11 17:33:30 -0600141 return hal_flash_align(area->fa_id);
David Brown5153bd62017-01-06 11:16:53 -0700142}
143
144/*
145 * This depends on the mappings defined in sysflash.h, and assumes
146 * that slot 0, slot 1, and the scratch area area contiguous.
147 */
148int flash_area_id_from_image_slot(int slot)
149{
David Brown0d0652a2017-04-11 17:33:30 -0600150 return slot + FLASH_AREA_IMAGE_0;
David Brown5153bd62017-01-06 11:16:53 -0700151}
152
Marti Bolivar29d3a772017-03-20 10:44:25 -0400153#ifndef FLASH_AREA_IMAGE_SECTOR_SIZE
154#warning "Missing FLASH_AREA_IMAGE_SECTOR_SIZE; assuming scratch size instead"
155#define FLASH_AREA_IMAGE_SECTOR_SIZE FLASH_AREA_IMAGE_SCRATCH_SIZE
156#endif
157
Marti Bolivarfa264cb2017-05-03 17:58:14 -0400158static int validate_idx(int idx, uint32_t *off, uint32_t *len)
David Brown5153bd62017-01-06 11:16:53 -0700159{
David Brown0d0652a2017-04-11 17:33:30 -0600160 /*
161 * This simple layout has uniform slots, so just fill in the
162 * right one.
163 */
David Brown74b3c582017-04-11 17:39:25 -0600164 if (idx < FLASH_AREA_IMAGE_0 || idx > FLASH_AREA_IMAGE_SCRATCH) {
David Brown0d0652a2017-04-11 17:33:30 -0600165 return -1;
David Brown74b3c582017-04-11 17:39:25 -0600166 }
David Brown5153bd62017-01-06 11:16:53 -0700167
David Brown0d0652a2017-04-11 17:33:30 -0600168 switch (idx) {
169 case FLASH_AREA_IMAGE_0:
Marti Bolivarfa264cb2017-05-03 17:58:14 -0400170 *off = FLASH_AREA_IMAGE_0_OFFSET;
171 *len = FLASH_AREA_IMAGE_0_SIZE;
172 goto done;
David Brown0d0652a2017-04-11 17:33:30 -0600173 case FLASH_AREA_IMAGE_1:
Marti Bolivarfa264cb2017-05-03 17:58:14 -0400174 *off = FLASH_AREA_IMAGE_1_OFFSET;
175 *len = FLASH_AREA_IMAGE_1_SIZE;
176 goto done;
David Brown0d0652a2017-04-11 17:33:30 -0600177 case FLASH_AREA_IMAGE_SCRATCH:
Marti Bolivarfa264cb2017-05-03 17:58:14 -0400178 *off = FLASH_AREA_IMAGE_SCRATCH_OFFSET;
179 *len = FLASH_AREA_IMAGE_SCRATCH_SIZE;
180 goto done;
David Brown0d0652a2017-04-11 17:33:30 -0600181 default:
182 BOOT_LOG_ERR("unknown flash area %d", idx);
183 return -1;
184 }
David Brown5153bd62017-01-06 11:16:53 -0700185
Marti Bolivarfa264cb2017-05-03 17:58:14 -0400186 done:
David Brown0d0652a2017-04-11 17:33:30 -0600187 BOOT_LOG_DBG("area %d: offset=0x%x, length=0x%x, sector size=0x%x",
Marti Bolivarfa264cb2017-05-03 17:58:14 -0400188 idx, *off, *len, FLASH_AREA_IMAGE_SECTOR_SIZE);
189 return 0;
190}
191
192int flash_area_to_sectors(int idx, int *cnt, struct flash_area *ret)
193{
194 uint32_t off;
195 uint32_t len;
196 uint32_t max_cnt = *cnt;
197 uint32_t rem_len;
198
199 if (validate_idx(idx, &off, &len)) {
200 return -1;
201 }
202
203 if (*cnt < 1) {
204 return -1;
205 }
Marti Bolivar29d3a772017-03-20 10:44:25 -0400206
David Brown0d0652a2017-04-11 17:33:30 -0600207 rem_len = len;
208 *cnt = 0;
209 while (rem_len > 0 && *cnt < max_cnt) {
210 if (rem_len < FLASH_AREA_IMAGE_SECTOR_SIZE) {
211 BOOT_LOG_ERR("area %d size 0x%x not divisible by sector size 0x%x",
212 idx, len, FLASH_AREA_IMAGE_SECTOR_SIZE);
213 return -1;
214 }
Marti Bolivar29d3a772017-03-20 10:44:25 -0400215
David Brown0d0652a2017-04-11 17:33:30 -0600216 ret[*cnt].fa_id = idx;
217 ret[*cnt].fa_device_id = 0;
218 ret[*cnt].pad16 = 0;
219 ret[*cnt].fa_off = off + (FLASH_AREA_IMAGE_SECTOR_SIZE * (*cnt));
220 ret[*cnt].fa_size = FLASH_AREA_IMAGE_SECTOR_SIZE;
221 *cnt = *cnt + 1;
222 rem_len -= FLASH_AREA_IMAGE_SECTOR_SIZE;
223 }
Marti Bolivar29d3a772017-03-20 10:44:25 -0400224
David Brown0d0652a2017-04-11 17:33:30 -0600225 if (*cnt >= max_cnt) {
226 BOOT_LOG_ERR("flash area %d sector count overflow", idx);
227 return -1;
228 }
David Brown5153bd62017-01-06 11:16:53 -0700229
David Brown0d0652a2017-04-11 17:33:30 -0600230 return 0;
David Brown5153bd62017-01-06 11:16:53 -0700231}
Marti Bolivarfa264cb2017-05-03 17:58:14 -0400232
233/*
234 * Lookup the sector map for a given flash area. This should fill in
235 * `ret` with all of the sectors in the area. `*cnt` will be set to
236 * the storage at `ret` and should be set to the final number of
237 * sectors in this area.
238 */
239int flash_area_get_sectors(int idx, uint32_t *cnt, struct flash_sector *ret)
240{
241 uint32_t off;
242 uint32_t len;
243 uint32_t max_cnt = *cnt;
244 uint32_t rem_len;
245
246 if (validate_idx(idx, &off, &len)) {
247 return -1;
248 }
249
250 if (*cnt < 1) {
251 return -1;
252 }
253
254 rem_len = len;
255 *cnt = 0;
256 while (rem_len > 0 && *cnt < max_cnt) {
257 if (rem_len < FLASH_AREA_IMAGE_SECTOR_SIZE) {
258 BOOT_LOG_ERR("area %d size 0x%x not divisible by sector size 0x%x",
259 idx, len, FLASH_AREA_IMAGE_SECTOR_SIZE);
260 return -1;
261 }
262
263 ret[*cnt].fs_off = FLASH_AREA_IMAGE_SECTOR_SIZE * (*cnt);
264 ret[*cnt].fs_size = FLASH_AREA_IMAGE_SECTOR_SIZE;
265 *cnt = *cnt + 1;
266 rem_len -= FLASH_AREA_IMAGE_SECTOR_SIZE;
267 }
268
269 if (*cnt >= max_cnt) {
270 BOOT_LOG_ERR("flash area %d sector count overflow", idx);
271 return -1;
272 }
273
274 return 0;
275}