blob: fca3724710e99d1fcb15c12813472c3bf8095c90 [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/*
35 * The flash area describes essentially the partition table of the
36 * flash. In this case, it starts with FLASH_AREA_IMAGE_0.
37 */
David Brown1d9f1852017-05-23 10:32:22 -060038static const struct flash_area part_map[] = {
David Brown0d0652a2017-04-11 17:33:30 -060039 {
David Brown1d9f1852017-05-23 10:32:22 -060040 .fa_id = FLASH_AREA_IMAGE_0,
41 .fa_off = FLASH_AREA_IMAGE_0_OFFSET,
42 .fa_size = FLASH_AREA_IMAGE_0_SIZE,
David Brown0d0652a2017-04-11 17:33:30 -060043 },
44 {
David Brown1d9f1852017-05-23 10:32:22 -060045 .fa_id = FLASH_AREA_IMAGE_1,
46 .fa_off = FLASH_AREA_IMAGE_1_OFFSET,
47 .fa_size = FLASH_AREA_IMAGE_1_SIZE,
David Brown0d0652a2017-04-11 17:33:30 -060048 },
49 {
David Brown1d9f1852017-05-23 10:32:22 -060050 .fa_id = FLASH_AREA_IMAGE_SCRATCH,
51 .fa_off = FLASH_AREA_IMAGE_SCRATCH_OFFSET,
52 .fa_size = FLASH_AREA_IMAGE_SCRATCH_SIZE,
53 },
David Brown5153bd62017-01-06 11:16:53 -070054};
55
56/*
David Brown5153bd62017-01-06 11:16:53 -070057 * `open` a flash area. The `area` in this case is not the individual
58 * sectors, but describes the particular flash area in question.
59 */
60int flash_area_open(uint8_t id, const struct flash_area **area)
61{
David Brown0d0652a2017-04-11 17:33:30 -060062 int i;
Ricardo Salveti7cf3d9e2017-01-18 16:38:22 -020063
David Brown0d0652a2017-04-11 17:33:30 -060064 BOOT_LOG_DBG("area %d", id);
David Brown5153bd62017-01-06 11:16:53 -070065
David Brown0d0652a2017-04-11 17:33:30 -060066 for (i = 0; i < ARRAY_SIZE(part_map); i++) {
David Brown1d9f1852017-05-23 10:32:22 -060067 if (id == part_map[i].fa_id) {
David Brown0d0652a2017-04-11 17:33:30 -060068 break;
David Brown74b3c582017-04-11 17:39:25 -060069 }
David Brown0d0652a2017-04-11 17:33:30 -060070 }
David Brown74b3c582017-04-11 17:39:25 -060071 if (i == ARRAY_SIZE(part_map)) {
David Brown0d0652a2017-04-11 17:33:30 -060072 return -1;
David Brown74b3c582017-04-11 17:39:25 -060073 }
David Brown5153bd62017-01-06 11:16:53 -070074
David Brown1d9f1852017-05-23 10:32:22 -060075 *area = &part_map[i];
David Brown0d0652a2017-04-11 17:33:30 -060076 return 0;
David Brown5153bd62017-01-06 11:16:53 -070077}
78
79/*
80 * Nothing to do on close.
81 */
82void flash_area_close(const struct flash_area *area)
83{
84}
85
86int flash_area_read(const struct flash_area *area, uint32_t off, void *dst,
David Brown0d0652a2017-04-11 17:33:30 -060087 uint32_t len)
David Brown5153bd62017-01-06 11:16:53 -070088{
David Brown0d0652a2017-04-11 17:33:30 -060089 BOOT_LOG_DBG("area=%d, off=%x, len=%x", area->fa_id, off, len);
90 return flash_read(boot_flash_device, area->fa_off + off, dst, len);
David Brown5153bd62017-01-06 11:16:53 -070091}
92
93int flash_area_write(const struct flash_area *area, uint32_t off, const void *src,
David Brown0d0652a2017-04-11 17:33:30 -060094 uint32_t len)
David Brown5153bd62017-01-06 11:16:53 -070095{
David Brown0d0652a2017-04-11 17:33:30 -060096 int rc = 0;
Michael Scotte12746c2017-01-31 16:07:08 -080097
David Brown0d0652a2017-04-11 17:33:30 -060098 BOOT_LOG_DBG("area=%d, off=%x, len=%x", area->fa_id, off, len);
99 flash_write_protection_set(boot_flash_device, false);
100 rc = flash_write(boot_flash_device, area->fa_off + off, src, len);
101 flash_write_protection_set(boot_flash_device, true);
102 return rc;
David Brown5153bd62017-01-06 11:16:53 -0700103}
104
105int flash_area_erase(const struct flash_area *area, uint32_t off, uint32_t len)
106{
David Brown0d0652a2017-04-11 17:33:30 -0600107 int rc;
Marti Bolivar53cfdb92017-02-10 15:05:22 -0500108
David Brown0d0652a2017-04-11 17:33:30 -0600109 BOOT_LOG_DBG("area=%d, off=%x, len=%x", area->fa_id, off, len);
110 flash_write_protection_set(boot_flash_device, false);
111 rc = flash_erase(boot_flash_device, area->fa_off + off, len);
112 flash_write_protection_set(boot_flash_device, true);
113 return rc;
David Brown5153bd62017-01-06 11:16:53 -0700114}
115
116uint8_t flash_area_align(const struct flash_area *area)
117{
David Brown0d0652a2017-04-11 17:33:30 -0600118 return hal_flash_align(area->fa_id);
David Brown5153bd62017-01-06 11:16:53 -0700119}
120
121/*
122 * This depends on the mappings defined in sysflash.h, and assumes
123 * that slot 0, slot 1, and the scratch area area contiguous.
124 */
125int flash_area_id_from_image_slot(int slot)
126{
David Brown0d0652a2017-04-11 17:33:30 -0600127 return slot + FLASH_AREA_IMAGE_0;
David Brown5153bd62017-01-06 11:16:53 -0700128}
129
Marti Bolivar29d3a772017-03-20 10:44:25 -0400130#ifndef FLASH_AREA_IMAGE_SECTOR_SIZE
131#warning "Missing FLASH_AREA_IMAGE_SECTOR_SIZE; assuming scratch size instead"
132#define FLASH_AREA_IMAGE_SECTOR_SIZE FLASH_AREA_IMAGE_SCRATCH_SIZE
133#endif
134
David Brown1d9f1852017-05-23 10:32:22 -0600135/*
136 * Lookup the sector map for a given flash area. This should fill in
137 * `ret` with all of the sectors in the area. `*cnt` will be set to
138 * the storage at `ret` and should be set to the final number of
139 * sectors in this area.
140 */
141int flash_area_to_sectors(int idx, int *cnt, struct flash_area *ret)
David Brown5153bd62017-01-06 11:16:53 -0700142{
David Brown1d9f1852017-05-23 10:32:22 -0600143 uint32_t off;
144 uint32_t len;
145 uint32_t max_cnt = *cnt;
146 uint32_t rem_len;
147
David Brown0d0652a2017-04-11 17:33:30 -0600148 /*
149 * This simple layout has uniform slots, so just fill in the
150 * right one.
151 */
David Brown74b3c582017-04-11 17:39:25 -0600152 if (idx < FLASH_AREA_IMAGE_0 || idx > FLASH_AREA_IMAGE_SCRATCH) {
David Brown0d0652a2017-04-11 17:33:30 -0600153 return -1;
David Brown74b3c582017-04-11 17:39:25 -0600154 }
David Brown5153bd62017-01-06 11:16:53 -0700155
David Brown1d9f1852017-05-23 10:32:22 -0600156 if (*cnt < 1) {
157 return -1;
158 }
159
David Brown0d0652a2017-04-11 17:33:30 -0600160 switch (idx) {
161 case FLASH_AREA_IMAGE_0:
David Brown1d9f1852017-05-23 10:32:22 -0600162 off = FLASH_AREA_IMAGE_0_OFFSET;
163 len = FLASH_AREA_IMAGE_0_SIZE;
164 break;
David Brown0d0652a2017-04-11 17:33:30 -0600165 case FLASH_AREA_IMAGE_1:
David Brown1d9f1852017-05-23 10:32:22 -0600166 off = FLASH_AREA_IMAGE_1_OFFSET;
167 len = FLASH_AREA_IMAGE_1_SIZE;
168 break;
David Brown0d0652a2017-04-11 17:33:30 -0600169 case FLASH_AREA_IMAGE_SCRATCH:
David Brown1d9f1852017-05-23 10:32:22 -0600170 off = FLASH_AREA_IMAGE_SCRATCH_OFFSET;
171 len = FLASH_AREA_IMAGE_SCRATCH_SIZE;
172 break;
David Brown0d0652a2017-04-11 17:33:30 -0600173 default:
174 BOOT_LOG_ERR("unknown flash area %d", idx);
175 return -1;
176 }
David Brown5153bd62017-01-06 11:16:53 -0700177
David Brown0d0652a2017-04-11 17:33:30 -0600178 BOOT_LOG_DBG("area %d: offset=0x%x, length=0x%x, sector size=0x%x",
David Brown1d9f1852017-05-23 10:32:22 -0600179 idx, off, len, FLASH_AREA_IMAGE_SECTOR_SIZE);
Marti Bolivar29d3a772017-03-20 10:44:25 -0400180
David Brown0d0652a2017-04-11 17:33:30 -0600181 rem_len = len;
182 *cnt = 0;
183 while (rem_len > 0 && *cnt < max_cnt) {
184 if (rem_len < FLASH_AREA_IMAGE_SECTOR_SIZE) {
185 BOOT_LOG_ERR("area %d size 0x%x not divisible by sector size 0x%x",
186 idx, len, FLASH_AREA_IMAGE_SECTOR_SIZE);
187 return -1;
188 }
Marti Bolivar29d3a772017-03-20 10:44:25 -0400189
David Brown0d0652a2017-04-11 17:33:30 -0600190 ret[*cnt].fa_id = idx;
191 ret[*cnt].fa_device_id = 0;
192 ret[*cnt].pad16 = 0;
193 ret[*cnt].fa_off = off + (FLASH_AREA_IMAGE_SECTOR_SIZE * (*cnt));
194 ret[*cnt].fa_size = FLASH_AREA_IMAGE_SECTOR_SIZE;
195 *cnt = *cnt + 1;
196 rem_len -= FLASH_AREA_IMAGE_SECTOR_SIZE;
197 }
Marti Bolivar29d3a772017-03-20 10:44:25 -0400198
David Brown0d0652a2017-04-11 17:33:30 -0600199 if (*cnt >= max_cnt) {
200 BOOT_LOG_ERR("flash area %d sector count overflow", idx);
201 return -1;
202 }
David Brown5153bd62017-01-06 11:16:53 -0700203
David Brown0d0652a2017-04-11 17:33:30 -0600204 return 0;
David Brown5153bd62017-01-06 11:16:53 -0700205}