blob: 108bc9bb4acd0b33265af1954017b7d9436812a9 [file] [log] [blame]
Sughosh Ganua56a10b2024-03-22 16:27:20 +05301// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2024, Linaro Limited
4 */
5
6#include <fwu.h>
7#include <fwu_mdata.h>
8#include <log.h>
9
10#include <linux/types.h>
11
12#define FWU_MDATA_VERSION 0x2U
13
14static inline struct fwu_fw_store_desc *fwu_get_fw_desc(struct fwu_mdata *mdata)
15{
16 return (struct fwu_fw_store_desc *)((u8 *)mdata + sizeof(*mdata));
17}
18
19static uint32_t fwu_check_trial_state(struct fwu_mdata *mdata, uint32_t bank)
20{
21 return mdata->bank_state[bank] == FWU_BANK_VALID ? 1 : 0;
22}
23
24static void fwu_data_init(void)
25{
26 int i;
27 size_t image_info_size;
28 void *dst_img_info, *src_img_info;
29 struct fwu_data *data = fwu_get_data();
30 struct fwu_mdata *mdata = data->fwu_mdata;
31
32 data->crc32 = mdata->crc32;
33 data->version = mdata->version;
34 data->active_index = mdata->active_index;
35 data->previous_active_index = mdata->previous_active_index;
36 data->metadata_size = mdata->metadata_size;
37 fwu_plat_get_bootidx(&data->boot_index);
38 data->trial_state = fwu_check_trial_state(mdata, data->boot_index);
39
40 data->num_banks = fwu_get_fw_desc(mdata)->num_banks;
41 data->num_images = fwu_get_fw_desc(mdata)->num_images;
42
43 for (i = 0; i < 4; i++) {
44 data->bank_state[i] = mdata->bank_state[i];
45 }
46
47 image_info_size = sizeof(data->fwu_images);
48 src_img_info = &fwu_get_fw_desc(mdata)->img_entry[0];
49 dst_img_info = &data->fwu_images[0];
50
51 memcpy(dst_img_info, src_img_info, image_info_size);
52}
53
54static int fwu_mdata_sanity_checks(void)
55{
56 uint8_t num_banks;
57 uint16_t num_images;
58 struct fwu_data *data = fwu_get_data();
59 struct fwu_mdata *mdata = data->fwu_mdata;
60
61 if (mdata->version != FWU_MDATA_VERSION) {
62 log_err("FWU metadata version %u. Expected value of %u\n",
63 mdata->version, FWU_MDATA_VERSION);
64 return -EINVAL;
65 }
66
67 if (!mdata->desc_offset) {
68 log_err("No image information provided with the Metadata. ");
69 log_err("Image information expected in the metadata\n");
70 return -EINVAL;
71 }
72
73 if (mdata->desc_offset != 0x20) {
74 log_err("Descriptor Offset(0x%x) in the FWU Metadata not equal to 0x20\n",
75 mdata->desc_offset);
76 return -EINVAL;
77 }
78
79 num_banks = fwu_get_fw_desc(mdata)->num_banks;
80 num_images = fwu_get_fw_desc(mdata)->num_images;
81
82 if (num_banks != CONFIG_FWU_NUM_BANKS) {
83 log_err("Number of Banks(%u) in FWU Metadata different from the configured value(%d)",
84 num_banks, CONFIG_FWU_NUM_BANKS);
85 return -EINVAL;
86 }
87
88 if (num_images != CONFIG_FWU_NUM_IMAGES_PER_BANK) {
89 log_err("Number of Images(%u) in FWU Metadata different from the configured value(%d)",
90 num_images, CONFIG_FWU_NUM_IMAGES_PER_BANK);
91 return -EINVAL;
92 }
93
94 return 0;
95}
96
97static int fwu_bank_state_update(bool trial_state, uint32_t bank)
98{
99 int ret;
100 struct fwu_data *data = fwu_get_data();
101 struct fwu_mdata *mdata = data->fwu_mdata;
102
103 mdata->bank_state[bank] = data->bank_state[bank] = trial_state ?
104 FWU_BANK_VALID : FWU_BANK_ACCEPTED;
105
106 ret = fwu_sync_mdata(mdata, BOTH_PARTS);
107 if (ret)
108 log_err("Unable to set bank_state for bank %u\n", bank);
109 else
110 data->trial_state = trial_state;
111
112 return ret;
113}
114
115static int fwu_trial_state_start(uint update_index)
116{
117 int ret;
118
119 ret = fwu_trial_state_ctr_start();
120 if (ret)
121 return ret;
122
123 ret = fwu_bank_state_update(1, update_index);
124 if (ret)
125 return ret;
126
127 return 0;
128}
129
130/**
131 * fwu_populate_mdata_image_info() - Populate the image information
132 * of the metadata
133 * @data: Version agnostic FWU metadata information
134 *
135 * Populate the image information in the FWU metadata by copying it
136 * from the version agnostic structure. This is done before the
137 * metadata gets written to the storage media.
138 *
139 * Return: None
140 */
141void fwu_populate_mdata_image_info(struct fwu_data *data)
142{
143 size_t image_info_size;
144 struct fwu_mdata *mdata = data->fwu_mdata;
145 void *dst_img_info, *src_img_info;
146
147 image_info_size = sizeof(data->fwu_images);
148 dst_img_info = &fwu_get_fw_desc(mdata)->img_entry[0];
149 src_img_info = &data->fwu_images[0];
150
151 memcpy(dst_img_info, src_img_info, image_info_size);
152}
153
154/**
155 * fwu_state_machine_updates() - Update FWU state of the platform
156 * @trial_state: Is platform transitioning into Trial State
157 * @update_index: Bank number to which images have been updated
158 *
159 * On successful completion of updates, transition the platform to
160 * either Trial State or Regular State.
161 *
162 * To transition the platform to Trial State, start the
163 * TrialStateCtr counter, followed by setting the value of bank_state
164 * field of the metadata to Valid state(applicable only in version 2
165 * of metadata).
166 *
167 * In case, the platform is to transition directly to Regular State,
168 * update the bank_state field of the metadata to Accepted
169 * state(applicable only in version 2 of metadata).
170 *
171 * Return: 0 if OK, -ve on error
172 */
173int fwu_state_machine_updates(bool trial_state, uint32_t update_index)
174{
175 return trial_state ? fwu_trial_state_start(update_index) :
176 fwu_bank_state_update(0, update_index);
177}
178
179/**
180 * fwu_get_mdata_size() - Get the FWU metadata size
181 * @mdata_size: Size of the metadata structure
182 *
183 * Get the size of the FWU metadata from the structure. This is later used
184 * to allocate memory for the structure.
185 *
186 * Return: 0 if OK, -ve on error
187 */
188int fwu_get_mdata_size(uint32_t *mdata_size)
189{
190 int ret = 0;
191 struct fwu_mdata mdata = { 0 };
192 struct fwu_data *data = fwu_get_data();
193 struct udevice *fwu_dev = fwu_get_dev();
194
195 if (data->metadata_size) {
196 *mdata_size = data->metadata_size;
197 return 0;
198 }
199
200 ret = fwu_read_mdata(fwu_dev, &mdata, 1,
201 sizeof(struct fwu_mdata));
202 if (ret) {
203 log_err("FWU metadata read failed\n");
204 return ret;
205 }
206
207 *mdata_size = mdata.metadata_size;
208 if (!*mdata_size)
209 return -EINVAL;
210
211 return 0;
212}
213
214/**
215 * fwu_init() - FWU specific initialisations
216 *
217 * Carry out some FWU specific initialisations including allocation
218 * of memory for the metadata copies, and reading the FWU metadata
219 * copies into the allocated memory. The metadata fields are then
220 * copied into a version agnostic structure.
221 *
222 * Return: 0 if OK, -ve on error
223 */
224int fwu_init(void)
225{
226 int ret;
227 struct fwu_mdata mdata = { 0 };
228 struct udevice *fwu_dev = fwu_get_dev();
229
230 /*
231 * First we read only the top level structure
232 * and get the size of the complete structure.
233 */
234 ret = fwu_read_mdata(fwu_dev, &mdata, 1,
235 sizeof(struct fwu_mdata));
236 if (ret) {
237 log_err("FWU metadata read failed\n");
238 return ret;
239 }
240
241 ret = fwu_mdata_copies_allocate(mdata.metadata_size);
242 if (ret)
243 return ret;
244
245 /*
246 * Now read the entire structure, both copies, and
247 * validate that the copies.
248 */
249 ret = fwu_get_mdata(NULL);
250 if (ret)
251 return ret;
252
253 ret = fwu_mdata_sanity_checks();
254 if (ret)
255 return ret;
256
257 fwu_data_init();
258
259 return 0;
260}