blob: 5b027fad048205b91e397571e273dfe377bc568a [file] [log] [blame]
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2/*
3 * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
4 */
5
Simon Glassed38aef2020-05-10 11:40:03 -06006#include <command.h>
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01007#include <console.h>
8#include <dfu.h>
Patrick Delaunayb9ef46b2022-03-28 19:25:32 +02009#include <image.h>
Patrick Delaunay7daa91d2020-03-18 09:24:49 +010010#include <malloc.h>
Patrick Delaunay541c7de2020-03-18 09:24:59 +010011#include <misc.h>
Patrick Delaunay7aae1e32020-03-18 09:24:51 +010012#include <mmc.h>
Patrick Delaunay6ab74962020-03-18 09:24:54 +010013#include <part.h>
Patrick Delaunay8da5df92022-03-28 19:25:28 +020014#include <tee.h>
Patrick Delaunay1d96b182020-03-18 09:24:58 +010015#include <asm/arch/stm32mp1_smc.h>
Patrick Delaunay285025f2024-03-20 15:56:42 +010016#include <asm/arch/sys_proto.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060017#include <asm/global_data.h>
Patrick Delaunay8da5df92022-03-28 19:25:28 +020018#include <dm/device_compat.h>
Patrick Delaunay7daa91d2020-03-18 09:24:49 +010019#include <dm/uclass.h>
Patrick Delaunay6ab74962020-03-18 09:24:54 +010020#include <jffs2/load_kernel.h>
Patrick Delaunay7daa91d2020-03-18 09:24:49 +010021#include <linux/list.h>
22#include <linux/list_sort.h>
Patrick Delaunay6ab74962020-03-18 09:24:54 +010023#include <linux/mtd/mtd.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060024#include <linux/printk.h>
Patrick Delaunay7daa91d2020-03-18 09:24:49 +010025#include <linux/sizes.h>
26
27#include "stm32prog.h"
28
Patrick Delaunay7aae1e32020-03-18 09:24:51 +010029/* Primary GPT header size for 128 entries : 17kB = 34 LBA of 512B */
30#define GPT_HEADER_SZ 34
31
Patrick Delaunay7daa91d2020-03-18 09:24:49 +010032#define OPT_SELECT BIT(0)
33#define OPT_EMPTY BIT(1)
Patrick Delaunay291e7222020-03-18 09:24:57 +010034#define OPT_DELETE BIT(2)
Patrick Delaunay7daa91d2020-03-18 09:24:49 +010035
36#define IS_SELECT(part) ((part)->option & OPT_SELECT)
37#define IS_EMPTY(part) ((part)->option & OPT_EMPTY)
Patrick Delaunay291e7222020-03-18 09:24:57 +010038#define IS_DELETE(part) ((part)->option & OPT_DELETE)
Patrick Delaunay7daa91d2020-03-18 09:24:49 +010039
40#define ALT_BUF_LEN SZ_1K
41
Patrick Delaunay7aae1e32020-03-18 09:24:51 +010042#define ROOTFS_MMC0_UUID \
43 EFI_GUID(0xE91C4E10, 0x16E6, 0x4C0E, \
44 0xBD, 0x0E, 0x77, 0xBE, 0xCF, 0x4A, 0x35, 0x82)
45
46#define ROOTFS_MMC1_UUID \
47 EFI_GUID(0x491F6117, 0x415D, 0x4F53, \
48 0x88, 0xC9, 0x6E, 0x0D, 0xE5, 0x4D, 0xEA, 0xC6)
49
50#define ROOTFS_MMC2_UUID \
51 EFI_GUID(0xFD58F1C7, 0xBE0D, 0x4338, \
52 0x88, 0xE9, 0xAD, 0x8F, 0x05, 0x0A, 0xEB, 0x18)
53
Patrick Delaunay33029a52022-03-28 19:25:26 +020054/* RAW partition (binary / bootloader) used Linux - reserved UUID */
Patrick Delaunay7aae1e32020-03-18 09:24:51 +010055#define LINUX_RESERVED_UUID "8DA63339-0007-60C0-C436-083AC8230908"
56
57/*
58 * unique partition guid (uuid) for partition named "rootfs"
59 * on each MMC instance = SD Card or eMMC
60 * allow fixed kernel bootcmd: "rootf=PARTUID=e91c4e10-..."
61 */
62static const efi_guid_t uuid_mmc[3] = {
63 ROOTFS_MMC0_UUID,
64 ROOTFS_MMC1_UUID,
65 ROOTFS_MMC2_UUID
66};
67
Patrick Delaunayc203c212023-06-08 17:09:56 +020068/*
69 * GUID value defined in the FWU specification for identification
70 * of the FWU metadata partition.
71 */
72#define FWU_MDATA_UUID "8a7a84a0-8387-40f6-ab41-a8b9a5a60d23"
73
Patrick Delaunay8dc57682022-03-28 19:25:30 +020074/* FIP type partition UUID used by TF-A*/
75#define FIP_TYPE_UUID "19D5DF83-11B0-457B-BE2C-7559C13142A5"
76
77/* unique partition guid (uuid) for FIP partitions A/B */
78#define FIP_A_UUID \
79 EFI_GUID(0x4FD84C93, 0x54EF, 0x463F, \
80 0xA7, 0xEF, 0xAE, 0x25, 0xFF, 0x88, 0x70, 0x87)
81
82#define FIP_B_UUID \
83 EFI_GUID(0x09C54952, 0xD5BF, 0x45AF, \
84 0xAC, 0xEE, 0x33, 0x53, 0x03, 0x76, 0x6F, 0xB3)
85
86static const char * const fip_part_name[] = {
87 "fip-a",
88 "fip-b"
89};
90
91static const efi_guid_t fip_part_uuid[] = {
92 FIP_A_UUID,
93 FIP_B_UUID
94};
95
Patrick Delaunay526f66c2020-03-18 09:24:50 +010096/* order of column in flash layout file */
97enum stm32prog_col_t {
98 COL_OPTION,
99 COL_ID,
100 COL_NAME,
101 COL_TYPE,
102 COL_IP,
103 COL_OFFSET,
104 COL_NB_STM32
105};
106
Patrick Delaunay19676ef2021-04-02 14:05:17 +0200107#define FIP_TOC_HEADER_NAME 0xAA640001
108
109struct fip_toc_header {
110 u32 name;
111 u32 serial_number;
112 u64 flags;
113};
114
Patrick Delaunay8da5df92022-03-28 19:25:28 +0200115#define TA_NVMEM_UUID { 0x1a8342cc, 0x81a5, 0x4512, \
116 { 0x99, 0xfe, 0x9e, 0x2b, 0x3e, 0x37, 0xd6, 0x26 } }
117
118/*
119 * Read NVMEM memory for STM32CubeProgrammer
120 *
121 * [in] value[0].a: Type (0 for OTP access)
122 * [out] memref[1].buffer Output buffer to return all read values
123 * [out] memref[1].size Size of buffer to be read
124 *
125 * Return codes:
126 * TEE_SUCCESS - Invoke command success
127 * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
128 */
129#define TA_NVMEM_READ 0x0
130
131/*
132 * Write NVMEM memory for STM32CubeProgrammer
133 *
134 * [in] value[0].a Type (0 for OTP access)
135 * [in] memref[1].buffer Input buffer with the values to write
136 * [in] memref[1].size Size of buffer to be written
137 *
138 * Return codes:
139 * TEE_SUCCESS - Invoke command success
140 * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
141 */
142#define TA_NVMEM_WRITE 0x1
143
144/* value of TA_NVMEM type = value[in] a */
145#define NVMEM_OTP 0
146
Patrick Delaunay19676ef2021-04-02 14:05:17 +0200147DECLARE_GLOBAL_DATA_PTR;
148
Patrick Delaunay8da5df92022-03-28 19:25:28 +0200149/* OPTEE TA NVMEM open helper */
150static int optee_ta_open(struct stm32prog_data *data)
151{
152 const struct tee_optee_ta_uuid uuid = TA_NVMEM_UUID;
153 struct tee_open_session_arg arg;
154 struct udevice *tee = NULL;
155 int rc;
156
157 if (data->tee)
158 return 0;
159
160 tee = tee_find_device(NULL, NULL, NULL, NULL);
161 if (!tee)
162 return -ENODEV;
163
164 memset(&arg, 0, sizeof(arg));
165 tee_optee_ta_uuid_to_octets(arg.uuid, &uuid);
166 rc = tee_open_session(tee, &arg, 0, NULL);
167 if (rc < 0)
168 return -ENODEV;
169
170 data->tee = tee;
171 data->tee_session = arg.session;
172
173 return 0;
174}
175
176/* OPTEE TA NVMEM invoke helper */
177static int optee_ta_invoke(struct stm32prog_data *data, int cmd, int type,
178 void *buff, ulong size)
179{
180 struct tee_invoke_arg arg;
181 struct tee_param param[2];
182 struct tee_shm *buff_shm;
183 int rc;
184
185 rc = tee_shm_register(data->tee, buff, size, 0, &buff_shm);
186 if (rc)
187 return rc;
188
189 memset(&arg, 0, sizeof(arg));
190 arg.func = cmd;
191 arg.session = data->tee_session;
192
193 memset(param, 0, sizeof(param));
194 param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
195 param[0].u.value.a = type;
196
197 if (cmd == TA_NVMEM_WRITE)
198 param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT;
199 else
200 param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
201
202 param[1].u.memref.shm = buff_shm;
203 param[1].u.memref.size = size;
204
205 rc = tee_invoke_func(data->tee, &arg, 2, param);
206 if (rc < 0 || arg.ret != 0) {
207 dev_err(data->tee,
208 "TA_NVMEM invoke failed TEE err: %x, err:%x\n",
209 arg.ret, rc);
210 if (!rc)
211 rc = -EIO;
212 }
213
214 tee_shm_free(buff_shm);
215
216 return rc;
217}
218
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100219char *stm32prog_get_error(struct stm32prog_data *data)
220{
221 static const char error_msg[] = "Unspecified";
222
223 if (strlen(data->error) == 0)
224 strcpy(data->error, error_msg);
225
226 return data->error;
227}
228
Patrick Delaunay19676ef2021-04-02 14:05:17 +0200229static bool stm32prog_is_fip_header(struct fip_toc_header *header)
230{
231 return (header->name == FIP_TOC_HEADER_NAME) && header->serial_number;
232}
233
Patrick Delaunay953d8bf2022-03-28 19:25:29 +0200234static bool stm32prog_is_stm32_header_v1(struct stm32_header_v1 *header)
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100235{
236 unsigned int i;
237
Patrick Delaunay953d8bf2022-03-28 19:25:29 +0200238 if (header->magic_number !=
239 (('S' << 0) | ('T' << 8) | ('M' << 16) | (0x32 << 24))) {
240 log_debug("%s:invalid magic number : 0x%x\n",
241 __func__, header->magic_number);
242 return false;
Patrick Delaunay19676ef2021-04-02 14:05:17 +0200243 }
Patrick Delaunay953d8bf2022-03-28 19:25:29 +0200244 if (header->header_version != 0x00010000) {
245 log_debug("%s:invalid header version : 0x%x\n",
246 __func__, header->header_version);
247 return false;
248 }
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100249
Patrick Delaunay953d8bf2022-03-28 19:25:29 +0200250 if (header->reserved1 || header->reserved2) {
251 log_debug("%s:invalid reserved field\n", __func__);
252 return false;
253 }
254 for (i = 0; i < sizeof(header->padding); i++) {
255 if (header->padding[i] != 0) {
256 log_debug("%s:invalid padding field\n", __func__);
257 return false;
258 }
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100259 }
Patrick Delaunay19676ef2021-04-02 14:05:17 +0200260
Patrick Delaunay953d8bf2022-03-28 19:25:29 +0200261 return true;
262}
263
264static bool stm32prog_is_stm32_header_v2(struct stm32_header_v2 *header)
265{
266 unsigned int i;
267
268 if (header->magic_number !=
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100269 (('S' << 0) | ('T' << 8) | ('M' << 16) | (0x32 << 24))) {
Patrick Delaunay2b15af52020-11-06 19:01:30 +0100270 log_debug("%s:invalid magic number : 0x%x\n",
Patrick Delaunay953d8bf2022-03-28 19:25:29 +0200271 __func__, header->magic_number);
272 return false;
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100273 }
Patrick Delaunay953d8bf2022-03-28 19:25:29 +0200274 if (header->header_version != 0x00020000) {
Patrick Delaunay2b15af52020-11-06 19:01:30 +0100275 log_debug("%s:invalid header version : 0x%x\n",
Patrick Delaunay953d8bf2022-03-28 19:25:29 +0200276 __func__, header->header_version);
277 return false;
278 }
279 if (header->reserved1 || header->reserved2)
280 return false;
281
282 for (i = 0; i < sizeof(header->padding); i++) {
283 if (header->padding[i] != 0) {
284 log_debug("%s:invalid padding field\n", __func__);
285 return false;
286 }
287 }
288
289 return true;
290}
291
292void stm32prog_header_check(uintptr_t raw_header, struct image_header_s *header)
293{
294 struct stm32_header_v1 *v1_header = (struct stm32_header_v1 *)raw_header;
295 struct stm32_header_v2 *v2_header = (struct stm32_header_v2 *)raw_header;
296
297 if (!raw_header || !header) {
298 log_debug("%s:no header data\n", __func__);
Patrick Delaunay19676ef2021-04-02 14:05:17 +0200299 return;
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100300 }
Patrick Delaunay953d8bf2022-03-28 19:25:29 +0200301
302 if (stm32prog_is_fip_header((struct fip_toc_header *)raw_header)) {
303 header->type = HEADER_FIP;
304 header->length = 0;
Patrick Delaunay19676ef2021-04-02 14:05:17 +0200305 return;
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100306 }
Patrick Delaunay953d8bf2022-03-28 19:25:29 +0200307 if (stm32prog_is_stm32_header_v1(v1_header)) {
308 header->type = HEADER_STM32IMAGE;
309 header->image_checksum = le32_to_cpu(v1_header->image_checksum);
310 header->image_length = le32_to_cpu(v1_header->image_length);
311 header->length = sizeof(struct stm32_header_v1);
312 return;
313 }
314 if (stm32prog_is_stm32_header_v2(v2_header)) {
315 header->type = HEADER_STM32IMAGE_V2;
316 header->image_checksum = le32_to_cpu(v2_header->image_checksum);
317 header->image_length = le32_to_cpu(v2_header->image_length);
318 header->length = sizeof(struct stm32_header_v1) +
319 v2_header->extension_headers_length;
320 return;
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100321 }
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100322
Patrick Delaunay953d8bf2022-03-28 19:25:29 +0200323 header->type = HEADER_NONE;
324 header->image_checksum = 0x0;
325 header->image_length = 0x0;
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100326}
327
Patrick Delaunay21ea4ef2022-09-06 18:53:19 +0200328static u32 stm32prog_header_checksum(uintptr_t addr, struct image_header_s *header)
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100329{
330 u32 i, checksum;
331 u8 *payload;
332
333 /* compute checksum on payload */
334 payload = (u8 *)addr;
335 checksum = 0;
336 for (i = header->image_length; i > 0; i--)
337 checksum += *(payload++);
338
339 return checksum;
340}
341
342/* FLASHLAYOUT PARSING *****************************************/
343static int parse_option(struct stm32prog_data *data,
344 int i, char *p, struct stm32prog_part_t *part)
345{
346 int result = 0;
347 char *c = p;
348
349 part->option = 0;
350 if (!strcmp(p, "-"))
351 return 0;
352
353 while (*c) {
354 switch (*c) {
355 case 'P':
356 part->option |= OPT_SELECT;
357 break;
358 case 'E':
359 part->option |= OPT_EMPTY;
360 break;
Patrick Delaunay291e7222020-03-18 09:24:57 +0100361 case 'D':
362 part->option |= OPT_DELETE;
363 break;
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100364 default:
365 result = -EINVAL;
366 stm32prog_err("Layout line %d: invalid option '%c' in %s)",
367 i, *c, p);
368 return -EINVAL;
369 }
370 c++;
371 }
372 if (!(part->option & OPT_SELECT)) {
373 stm32prog_err("Layout line %d: missing 'P' in option %s", i, p);
374 return -EINVAL;
375 }
376
377 return result;
378}
379
380static int parse_id(struct stm32prog_data *data,
381 int i, char *p, struct stm32prog_part_t *part)
382{
383 int result = 0;
384 unsigned long value;
385
386 result = strict_strtoul(p, 0, &value);
387 part->id = value;
388 if (result || value > PHASE_LAST_USER) {
389 stm32prog_err("Layout line %d: invalid phase value = %s", i, p);
390 result = -EINVAL;
391 }
392
393 return result;
394}
395
396static int parse_name(struct stm32prog_data *data,
397 int i, char *p, struct stm32prog_part_t *part)
398{
399 int result = 0;
400
401 if (strlen(p) < sizeof(part->name)) {
402 strcpy(part->name, p);
403 } else {
Patrick Delaunay21ea4ef2022-09-06 18:53:19 +0200404 stm32prog_err("Layout line %d: partition name too long [%zd]: %s",
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100405 i, strlen(p), p);
406 result = -EINVAL;
407 }
408
409 return result;
410}
411
412static int parse_type(struct stm32prog_data *data,
413 int i, char *p, struct stm32prog_part_t *part)
414{
415 int result = 0;
Patrick Delaunay851d6f32020-03-18 09:24:56 +0100416 int len = 0;
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100417
Patrick Delaunay851d6f32020-03-18 09:24:56 +0100418 part->bin_nb = 0;
419 if (!strncmp(p, "Binary", 6)) {
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100420 part->part_type = PART_BINARY;
Patrick Delaunay851d6f32020-03-18 09:24:56 +0100421
422 /* search for Binary(X) case */
423 len = strlen(p);
424 part->bin_nb = 1;
425 if (len > 6) {
426 if (len < 8 ||
427 (p[6] != '(') ||
428 (p[len - 1] != ')'))
429 result = -EINVAL;
430 else
431 part->bin_nb =
Simon Glassff9b9032021-07-24 09:03:30 -0600432 dectoul(&p[7], NULL);
Patrick Delaunay851d6f32020-03-18 09:24:56 +0100433 }
Patrick Delaunay8dc57682022-03-28 19:25:30 +0200434 } else if (!strcmp(p, "FIP")) {
435 part->part_type = PART_FIP;
Patrick Delaunayc203c212023-06-08 17:09:56 +0200436 } else if (!strcmp(p, "FWU_MDATA")) {
437 part->part_type = PART_FWU_MDATA;
Patrick Delaunayb386b9c2023-06-08 17:09:54 +0200438 } else if (!strcmp(p, "ENV")) {
439 part->part_type = PART_ENV;
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100440 } else if (!strcmp(p, "System")) {
441 part->part_type = PART_SYSTEM;
Patrick Delaunay0e582be2023-06-08 17:09:55 +0200442 } else if (!strcmp(p, "ESP")) {
443 part->part_type = PART_ESP;
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100444 } else if (!strcmp(p, "FileSystem")) {
445 part->part_type = PART_FILESYSTEM;
446 } else if (!strcmp(p, "RawImage")) {
447 part->part_type = RAW_IMAGE;
448 } else {
449 result = -EINVAL;
450 }
451 if (result)
452 stm32prog_err("Layout line %d: type parsing error : '%s'",
453 i, p);
454
455 return result;
456}
457
458static int parse_ip(struct stm32prog_data *data,
459 int i, char *p, struct stm32prog_part_t *part)
460{
461 int result = 0;
462 unsigned int len = 0;
463
464 part->dev_id = 0;
465 if (!strcmp(p, "none")) {
466 part->target = STM32PROG_NONE;
Patrick Delaunay7aae1e32020-03-18 09:24:51 +0100467 } else if (!strncmp(p, "mmc", 3)) {
468 part->target = STM32PROG_MMC;
469 len = 3;
Patrick Delaunay6ab74962020-03-18 09:24:54 +0100470 } else if (!strncmp(p, "nor", 3)) {
471 part->target = STM32PROG_NOR;
472 len = 3;
473 } else if (!strncmp(p, "nand", 4)) {
474 part->target = STM32PROG_NAND;
475 len = 4;
476 } else if (!strncmp(p, "spi-nand", 8)) {
477 part->target = STM32PROG_SPI_NAND;
478 len = 8;
Patrick Delaunay41e6ace2020-03-18 09:25:03 +0100479 } else if (!strncmp(p, "ram", 3)) {
480 part->target = STM32PROG_RAM;
481 len = 0;
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100482 } else {
483 result = -EINVAL;
484 }
485 if (len) {
486 /* only one digit allowed for device id */
487 if (strlen(p) != len + 1) {
488 result = -EINVAL;
489 } else {
490 part->dev_id = p[len] - '0';
491 if (part->dev_id > 9)
492 result = -EINVAL;
493 }
494 }
495 if (result)
496 stm32prog_err("Layout line %d: ip parsing error: '%s'", i, p);
497
498 return result;
499}
500
501static int parse_offset(struct stm32prog_data *data,
502 int i, char *p, struct stm32prog_part_t *part)
503{
504 int result = 0;
505 char *tail;
506
507 part->part_id = 0;
Patrick Delaunay6915b492020-03-18 09:24:52 +0100508 part->addr = 0;
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100509 part->size = 0;
Patrick Delaunay6915b492020-03-18 09:24:52 +0100510 /* eMMC boot parttion */
511 if (!strncmp(p, "boot", 4)) {
512 if (strlen(p) != 5) {
513 result = -EINVAL;
514 } else {
515 if (p[4] == '1')
516 part->part_id = -1;
517 else if (p[4] == '2')
518 part->part_id = -2;
519 else
520 result = -EINVAL;
521 }
522 if (result)
523 stm32prog_err("Layout line %d: invalid part '%s'",
524 i, p);
525 } else {
Patrick Delaunay53fe8e72023-04-27 15:36:37 +0200526 part->addr = simple_strtoull(p, &tail, 10);
Patrick Delaunay6915b492020-03-18 09:24:52 +0100527 if (tail == p || *tail != '\0') {
528 stm32prog_err("Layout line %d: invalid offset '%s'",
529 i, p);
530 result = -EINVAL;
531 }
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100532 }
533
534 return result;
535}
536
537static
538int (* const parse[COL_NB_STM32])(struct stm32prog_data *data, int i, char *p,
539 struct stm32prog_part_t *part) = {
540 [COL_OPTION] = parse_option,
541 [COL_ID] = parse_id,
542 [COL_NAME] = parse_name,
543 [COL_TYPE] = parse_type,
544 [COL_IP] = parse_ip,
545 [COL_OFFSET] = parse_offset,
546};
547
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100548static int parse_flash_layout(struct stm32prog_data *data,
Patrick Delaunay21ea4ef2022-09-06 18:53:19 +0200549 uintptr_t addr,
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100550 ulong size)
551{
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100552 int column = 0, part_nb = 0, ret;
553 bool end_of_line, eof;
554 char *p, *start, *last, *col;
555 struct stm32prog_part_t *part;
Patrick Delaunayf67fd842021-05-18 15:12:04 +0200556 struct image_header_s header;
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100557 int part_list_size;
558 int i;
559
560 data->part_nb = 0;
561
562 /* check if STM32image is detected */
Patrick Delaunay953d8bf2022-03-28 19:25:29 +0200563 stm32prog_header_check(addr, &header);
Patrick Delaunayf67fd842021-05-18 15:12:04 +0200564 if (header.type == HEADER_STM32IMAGE) {
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100565 u32 checksum;
566
Patrick Delaunay953d8bf2022-03-28 19:25:29 +0200567 addr = addr + header.length;
Patrick Delaunayf67fd842021-05-18 15:12:04 +0200568 size = header.image_length;
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100569
Patrick Delaunayf67fd842021-05-18 15:12:04 +0200570 checksum = stm32prog_header_checksum(addr, &header);
571 if (checksum != header.image_checksum) {
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100572 stm32prog_err("Layout: invalid checksum : 0x%x expected 0x%x",
Patrick Delaunayf67fd842021-05-18 15:12:04 +0200573 checksum, header.image_checksum);
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100574 return -EIO;
575 }
576 }
577 if (!size)
578 return -EINVAL;
579
580 start = (char *)addr;
581 last = start + size;
582
583 *last = 0x0; /* force null terminated string */
Patrick Delaunay2b15af52020-11-06 19:01:30 +0100584 log_debug("flash layout =\n%s\n", start);
Patrick Delaunay526f66c2020-03-18 09:24:50 +0100585
586 /* calculate expected number of partitions */
587 part_list_size = 1;
588 p = start;
589 while (*p && (p < last)) {
590 if (*p++ == '\n') {
591 part_list_size++;
592 if (p < last && *p == '#')
593 part_list_size--;
594 }
595 }
596 if (part_list_size > PHASE_LAST_USER) {
597 stm32prog_err("Layout: too many partition (%d)",
598 part_list_size);
599 return -1;
600 }
601 part = calloc(sizeof(struct stm32prog_part_t), part_list_size);
602 if (!part) {
603 stm32prog_err("Layout: alloc failed");
604 return -ENOMEM;
605 }
606 data->part_array = part;
607
608 /* main parsing loop */
609 i = 1;
610 eof = false;
611 p = start;
612 col = start; /* 1st column */
613 end_of_line = false;
614 while (!eof) {
615 switch (*p) {
616 /* CR is ignored and replaced by NULL character */
617 case '\r':
618 *p = '\0';
619 p++;
620 continue;
621 case '\0':
622 end_of_line = true;
623 eof = true;
624 break;
625 case '\n':
626 end_of_line = true;
627 break;
628 case '\t':
629 break;
630 case '#':
631 /* comment line is skipped */
632 if (column == 0 && p == col) {
633 while ((p < last) && *p)
634 if (*p++ == '\n')
635 break;
636 col = p;
637 i++;
638 if (p >= last || !*p) {
639 eof = true;
640 end_of_line = true;
641 }
642 continue;
643 }
644 /* fall through */
645 /* by default continue with the next character */
646 default:
647 p++;
648 continue;
649 }
650
651 /* replace by \0: allow string parsing for each column */
652 *p = '\0';
653 p++;
654 if (p >= last) {
655 eof = true;
656 end_of_line = true;
657 }
658
659 /* skip empty line and multiple TAB in tsv file */
660 if (strlen(col) == 0) {
661 col = p;
662 /* skip empty line */
663 if (column == 0 && end_of_line) {
664 end_of_line = false;
665 i++;
666 }
667 continue;
668 }
669
670 if (column < COL_NB_STM32) {
671 ret = parse[column](data, i, col, part);
672 if (ret)
673 return ret;
674 }
675
676 /* save the beginning of the next column */
677 column++;
678 col = p;
679
680 if (!end_of_line)
681 continue;
682
683 /* end of the line detected */
684 end_of_line = false;
685
686 if (column < COL_NB_STM32) {
687 stm32prog_err("Layout line %d: no enought column", i);
688 return -EINVAL;
689 }
690 column = 0;
691 part_nb++;
692 part++;
693 i++;
694 if (part_nb >= part_list_size) {
695 part = NULL;
696 if (!eof) {
697 stm32prog_err("Layout: no enought memory for %d part",
698 part_nb);
699 return -EINVAL;
700 }
701 }
702 }
703 data->part_nb = part_nb;
704 if (data->part_nb == 0) {
705 stm32prog_err("Layout: no partition found");
706 return -ENODEV;
707 }
708
709 return 0;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100710}
711
712static int __init part_cmp(void *priv, struct list_head *a, struct list_head *b)
713{
714 struct stm32prog_part_t *parta, *partb;
715
716 parta = container_of(a, struct stm32prog_part_t, list);
717 partb = container_of(b, struct stm32prog_part_t, list);
718
Patrick Delaunay6915b492020-03-18 09:24:52 +0100719 if (parta->part_id != partb->part_id)
720 return parta->part_id - partb->part_id;
721 else
722 return parta->addr > partb->addr ? 1 : -1;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100723}
724
Patrick Delaunay6ab74962020-03-18 09:24:54 +0100725static void get_mtd_by_target(char *string, enum stm32prog_target target,
726 int dev_id)
727{
728 const char *dev_str;
729
730 switch (target) {
731 case STM32PROG_NOR:
732 dev_str = "nor";
733 break;
734 case STM32PROG_NAND:
735 dev_str = "nand";
736 break;
737 case STM32PROG_SPI_NAND:
738 dev_str = "spi-nand";
739 break;
740 default:
741 dev_str = "invalid";
742 break;
743 }
744 sprintf(string, "%s%d", dev_str, dev_id);
745}
746
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100747static int init_device(struct stm32prog_data *data,
748 struct stm32prog_dev_t *dev)
749{
Patrick Delaunay7aae1e32020-03-18 09:24:51 +0100750 struct mmc *mmc = NULL;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100751 struct blk_desc *block_dev = NULL;
Patrick Delaunay6ab74962020-03-18 09:24:54 +0100752 struct mtd_info *mtd = NULL;
Patrice Chotard49569082023-06-08 17:16:40 +0200753 struct mtd_info *partition;
Patrick Delaunay6ab74962020-03-18 09:24:54 +0100754 char mtd_id[16];
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100755 int part_id;
Patrick Delaunay5ce50062020-03-18 09:24:53 +0100756 int ret;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100757 u64 first_addr = 0, last_addr = 0;
758 struct stm32prog_part_t *part, *next_part;
Patrick Delaunay5ce50062020-03-18 09:24:53 +0100759 u64 part_addr, part_size;
760 bool part_found;
761 const char *part_name;
Patrice Chotard49569082023-06-08 17:16:40 +0200762 u8 i;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100763
764 switch (dev->target) {
Patrick Delaunay7aae1e32020-03-18 09:24:51 +0100765 case STM32PROG_MMC:
Patrick Delaunay8040da12020-07-31 16:31:52 +0200766 if (!IS_ENABLED(CONFIG_MMC)) {
767 stm32prog_err("unknown device type = %d", dev->target);
768 return -ENODEV;
769 }
Patrick Delaunay7aae1e32020-03-18 09:24:51 +0100770 mmc = find_mmc_device(dev->dev_id);
Patrick Delaunayf4aaeed2020-07-06 13:20:58 +0200771 if (!mmc || mmc_init(mmc)) {
Patrick Delaunay7aae1e32020-03-18 09:24:51 +0100772 stm32prog_err("mmc device %d not found", dev->dev_id);
773 return -ENODEV;
774 }
775 block_dev = mmc_get_blk_desc(mmc);
776 if (!block_dev) {
777 stm32prog_err("mmc device %d not probed", dev->dev_id);
778 return -ENODEV;
779 }
780 dev->erase_size = mmc->erase_grp_size * block_dev->blksz;
781 dev->mmc = mmc;
782
783 /* reserve a full erase group for each GTP headers */
784 if (mmc->erase_grp_size > GPT_HEADER_SZ) {
785 first_addr = dev->erase_size;
786 last_addr = (u64)(block_dev->lba -
787 mmc->erase_grp_size) *
788 block_dev->blksz;
789 } else {
790 first_addr = (u64)GPT_HEADER_SZ * block_dev->blksz;
791 last_addr = (u64)(block_dev->lba - GPT_HEADER_SZ - 1) *
792 block_dev->blksz;
793 }
Patrice Chotardfd9a2fa2024-11-29 13:27:07 +0100794 log_debug("MMC %d: lba=%lld blksz=%ld\n", dev->dev_id,
795 (u64)block_dev->lba, block_dev->blksz);
Patrick Delaunay2b15af52020-11-06 19:01:30 +0100796 log_debug(" available address = 0x%llx..0x%llx\n",
797 first_addr, last_addr);
798 log_debug(" full_update = %d\n", dev->full_update);
Patrick Delaunay7aae1e32020-03-18 09:24:51 +0100799 break;
Patrick Delaunay6ab74962020-03-18 09:24:54 +0100800 case STM32PROG_NOR:
801 case STM32PROG_NAND:
802 case STM32PROG_SPI_NAND:
Patrick Delaunay8040da12020-07-31 16:31:52 +0200803 if (!IS_ENABLED(CONFIG_MTD)) {
804 stm32prog_err("unknown device type = %d", dev->target);
805 return -ENODEV;
806 }
Patrice Chotard49569082023-06-08 17:16:40 +0200807 /* register partitions with MTDIDS/MTDPARTS or OF fallback */
808 mtd_probe_devices();
Patrick Delaunay6ab74962020-03-18 09:24:54 +0100809 get_mtd_by_target(mtd_id, dev->target, dev->dev_id);
Patrick Delaunay2b15af52020-11-06 19:01:30 +0100810 log_debug("%s\n", mtd_id);
Patrick Delaunay6ab74962020-03-18 09:24:54 +0100811
Patrick Delaunay6ab74962020-03-18 09:24:54 +0100812 mtd = get_mtd_device_nm(mtd_id);
813 if (IS_ERR(mtd)) {
814 stm32prog_err("MTD device %s not found", mtd_id);
815 return -ENODEV;
816 }
817 first_addr = 0;
818 last_addr = mtd->size;
819 dev->erase_size = mtd->erasesize;
Patrick Delaunay2b15af52020-11-06 19:01:30 +0100820 log_debug("MTD device %s: size=%lld erasesize=%d\n",
821 mtd_id, mtd->size, mtd->erasesize);
822 log_debug(" available address = 0x%llx..0x%llx\n",
823 first_addr, last_addr);
Patrick Delaunay6ab74962020-03-18 09:24:54 +0100824 dev->mtd = mtd;
825 break;
Patrick Delaunay41e6ace2020-03-18 09:25:03 +0100826 case STM32PROG_RAM:
827 first_addr = gd->bd->bi_dram[0].start;
828 last_addr = first_addr + gd->bd->bi_dram[0].size;
829 dev->erase_size = 1;
830 break;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100831 default:
832 stm32prog_err("unknown device type = %d", dev->target);
833 return -ENODEV;
834 }
Patrick Delaunay2b15af52020-11-06 19:01:30 +0100835 log_debug(" erase size = 0x%x\n", dev->erase_size);
836 log_debug(" full_update = %d\n", dev->full_update);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100837
838 /* order partition list in offset order */
839 list_sort(NULL, &dev->part_list, &part_cmp);
840 part_id = 1;
Patrick Delaunay2b15af52020-11-06 19:01:30 +0100841 log_debug("id : Opt Phase Name target.n dev.n addr size part_off part_size\n");
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100842 list_for_each_entry(part, &dev->part_list, list) {
Patrick Delaunay851d6f32020-03-18 09:24:56 +0100843 if (part->bin_nb > 1) {
844 if ((dev->target != STM32PROG_NAND &&
845 dev->target != STM32PROG_SPI_NAND) ||
846 part->id >= PHASE_FIRST_USER ||
847 strncmp(part->name, "fsbl", 4)) {
848 stm32prog_err("%s (0x%x): multiple binary %d not supported",
849 part->name, part->id,
850 part->bin_nb);
851 return -EINVAL;
852 }
853 }
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100854 if (part->part_type == RAW_IMAGE) {
855 part->part_id = 0x0;
856 part->addr = 0x0;
857 if (block_dev)
858 part->size = block_dev->lba * block_dev->blksz;
859 else
860 part->size = last_addr;
Patrick Delaunay2b15af52020-11-06 19:01:30 +0100861 log_debug("-- : %1d %02x %14s %02d.%d %02d.%02d %08llx %08llx\n",
862 part->option, part->id, part->name,
863 part->part_type, part->bin_nb, part->target,
864 part->dev_id, part->addr, part->size);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100865 continue;
866 }
Patrick Delaunay6915b492020-03-18 09:24:52 +0100867 if (part->part_id < 0) { /* boot hw partition for eMMC */
868 if (mmc) {
869 part->size = mmc->capacity_boot;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100870 } else {
Patrick Delaunay6915b492020-03-18 09:24:52 +0100871 stm32prog_err("%s (0x%x): hw partition not expected : %d",
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100872 part->name, part->id,
Patrick Delaunay6915b492020-03-18 09:24:52 +0100873 part->part_id);
874 return -ENODEV;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100875 }
876 } else {
Patrick Delaunay6915b492020-03-18 09:24:52 +0100877 part->part_id = part_id++;
878
879 /* last partition : size to the end of the device */
880 if (part->list.next != &dev->part_list) {
881 next_part =
882 container_of(part->list.next,
883 struct stm32prog_part_t,
884 list);
885 if (part->addr < next_part->addr) {
886 part->size = next_part->addr -
887 part->addr;
888 } else {
889 stm32prog_err("%s (0x%x): same address : 0x%llx == %s (0x%x): 0x%llx",
890 part->name, part->id,
891 part->addr,
892 next_part->name,
893 next_part->id,
894 next_part->addr);
895 return -EINVAL;
896 }
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100897 } else {
Patrick Delaunay6915b492020-03-18 09:24:52 +0100898 if (part->addr <= last_addr) {
899 part->size = last_addr - part->addr;
900 } else {
901 stm32prog_err("%s (0x%x): invalid address 0x%llx (max=0x%llx)",
902 part->name, part->id,
903 part->addr, last_addr);
904 return -EINVAL;
905 }
906 }
907 if (part->addr < first_addr) {
908 stm32prog_err("%s (0x%x): invalid address 0x%llx (min=0x%llx)",
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100909 part->name, part->id,
Patrick Delaunay6915b492020-03-18 09:24:52 +0100910 part->addr, first_addr);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100911 return -EINVAL;
912 }
913 }
Patrick Delaunay7aae1e32020-03-18 09:24:51 +0100914 if ((part->addr & ((u64)part->dev->erase_size - 1)) != 0) {
915 stm32prog_err("%s (0x%x): not aligned address : 0x%llx on erase size 0x%x",
916 part->name, part->id, part->addr,
917 part->dev->erase_size);
918 return -EINVAL;
919 }
Patrick Delaunay2b15af52020-11-06 19:01:30 +0100920 log_debug("%02d : %1d %02x %14s %02d.%d %02d.%02d %08llx %08llx",
921 part->part_id, part->option, part->id, part->name,
922 part->part_type, part->bin_nb, part->target,
923 part->dev_id, part->addr, part->size);
Patrick Delaunay5ce50062020-03-18 09:24:53 +0100924
925 part_addr = 0;
926 part_size = 0;
927 part_found = false;
928
929 /* check coherency with existing partition */
930 if (block_dev) {
931 /*
932 * block devices with GPT: check user partition size
933 * only for partial update, the GPT partions are be
934 * created for full update
935 */
936 if (dev->full_update || part->part_id < 0) {
Patrick Delaunay2b15af52020-11-06 19:01:30 +0100937 log_debug("\n");
Patrick Delaunay5ce50062020-03-18 09:24:53 +0100938 continue;
939 }
Simon Glassc1c4a8f2020-05-10 11:39:57 -0600940 struct disk_partition partinfo;
Patrick Delaunay5ce50062020-03-18 09:24:53 +0100941
942 ret = part_get_info(block_dev, part->part_id,
943 &partinfo);
944
945 if (ret) {
946 stm32prog_err("%s (0x%x):Couldn't find part %d on device mmc %d",
947 part->name, part->id,
948 part_id, part->dev_id);
949 return -ENODEV;
950 }
951 part_addr = (u64)partinfo.start * partinfo.blksz;
952 part_size = (u64)partinfo.size * partinfo.blksz;
953 part_name = (char *)partinfo.name;
954 part_found = true;
955 }
956
Patrick Delaunay8040da12020-07-31 16:31:52 +0200957 if (IS_ENABLED(CONFIG_MTD) && mtd) {
Patrice Chotard49569082023-06-08 17:16:40 +0200958 i = 0;
959 list_for_each_entry(partition, &mtd->partitions, node) {
960 if ((part->part_id - 1) == i) {
961 part_found = true;
962 break;
963 }
964 i++;
965 }
966 if (part_found) {
967 part_addr = partition->offset;
968 part_size = partition->size;
969 part_name = partition->name;
970 } else {
971 stm32prog_err("%s (0x%x):Couldn't find part %d on device mtd %s",
972 part->name, part->id, part->part_id, mtd_id);
Patrick Delaunay6ab74962020-03-18 09:24:54 +0100973 return -ENODEV;
974 }
Patrick Delaunay6ab74962020-03-18 09:24:54 +0100975 }
Patrick Delaunay8040da12020-07-31 16:31:52 +0200976
Patrick Delaunayd5de9382020-10-15 14:28:17 +0200977 /* no partition for this device */
Patrick Delaunay5ce50062020-03-18 09:24:53 +0100978 if (!part_found) {
Patrick Delaunay2b15af52020-11-06 19:01:30 +0100979 log_debug("\n");
Patrick Delaunay5ce50062020-03-18 09:24:53 +0100980 continue;
981 }
982
Patrick Delaunay2b15af52020-11-06 19:01:30 +0100983 log_debug(" %08llx %08llx\n", part_addr, part_size);
Patrick Delaunay5ce50062020-03-18 09:24:53 +0100984
985 if (part->addr != part_addr) {
986 stm32prog_err("%s (0x%x): Bad address for partition %d (%s) = 0x%llx <> 0x%llx expected",
987 part->name, part->id, part->part_id,
988 part_name, part->addr, part_addr);
989 return -ENODEV;
990 }
991 if (part->size != part_size) {
992 stm32prog_err("%s (0x%x): Bad size for partition %d (%s) at 0x%llx = 0x%llx <> 0x%llx expected",
993 part->name, part->id, part->part_id,
994 part_name, part->addr, part->size,
995 part_size);
996 return -ENODEV;
997 }
Patrick Delaunay7daa91d2020-03-18 09:24:49 +0100998 }
999 return 0;
1000}
1001
1002static int treat_partition_list(struct stm32prog_data *data)
1003{
1004 int i, j;
1005 struct stm32prog_part_t *part;
1006
1007 for (j = 0; j < STM32PROG_MAX_DEV; j++) {
1008 data->dev[j].target = STM32PROG_NONE;
1009 INIT_LIST_HEAD(&data->dev[j].part_list);
1010 }
1011
Patrick Delaunayc5112242020-03-18 09:24:55 +01001012 data->fsbl_nor_detected = false;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001013 for (i = 0; i < data->part_nb; i++) {
1014 part = &data->part_array[i];
1015 part->alt_id = -1;
1016
1017 /* skip partition with IP="none" */
1018 if (part->target == STM32PROG_NONE) {
1019 if (IS_SELECT(part)) {
Patrick Delaunayf5b85712022-01-18 10:33:14 +01001020 stm32prog_err("Layout: selected none phase = 0x%x for part %s",
1021 part->id, part->name);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001022 return -EINVAL;
1023 }
1024 continue;
1025 }
1026
1027 if (part->id == PHASE_FLASHLAYOUT ||
1028 part->id > PHASE_LAST_USER) {
Patrick Delaunayf5b85712022-01-18 10:33:14 +01001029 stm32prog_err("Layout: invalid phase = 0x%x for part %s",
1030 part->id, part->name);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001031 return -EINVAL;
1032 }
1033 for (j = i + 1; j < data->part_nb; j++) {
1034 if (part->id == data->part_array[j].id) {
Patrick Delaunayf5b85712022-01-18 10:33:14 +01001035 stm32prog_err("Layout: duplicated phase 0x%x for part %s and %s",
1036 part->id, part->name, data->part_array[j].name);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001037 return -EINVAL;
1038 }
1039 }
1040 for (j = 0; j < STM32PROG_MAX_DEV; j++) {
1041 if (data->dev[j].target == STM32PROG_NONE) {
1042 /* new device found */
1043 data->dev[j].target = part->target;
1044 data->dev[j].dev_id = part->dev_id;
Patrick Delaunay5ce50062020-03-18 09:24:53 +01001045 data->dev[j].full_update = true;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001046 data->dev_nb++;
1047 break;
1048 } else if ((part->target == data->dev[j].target) &&
1049 (part->dev_id == data->dev[j].dev_id)) {
1050 break;
1051 }
1052 }
1053 if (j == STM32PROG_MAX_DEV) {
1054 stm32prog_err("Layout: too many device");
1055 return -EINVAL;
1056 }
Patrick Delaunayc5112242020-03-18 09:24:55 +01001057 switch (part->target) {
1058 case STM32PROG_NOR:
1059 if (!data->fsbl_nor_detected &&
1060 !strncmp(part->name, "fsbl", 4))
1061 data->fsbl_nor_detected = true;
1062 /* fallthrough */
Patrick Delaunayc5112242020-03-18 09:24:55 +01001063 default:
1064 break;
1065 }
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001066 part->dev = &data->dev[j];
Patrick Delaunay5ce50062020-03-18 09:24:53 +01001067 if (!IS_SELECT(part))
1068 part->dev->full_update = false;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001069 list_add_tail(&part->list, &data->dev[j].part_list);
1070 }
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001071
1072 return 0;
1073}
1074
Patrick Delaunay8040da12020-07-31 16:31:52 +02001075static int create_gpt_partitions(struct stm32prog_data *data)
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001076{
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001077 int offset = 0;
1078 const int buflen = SZ_8K;
1079 char *buf;
1080 char uuid[UUID_STR_LEN + 1];
1081 unsigned char *uuid_bin;
1082 unsigned int mmc_id;
Patrick Delaunay8dc57682022-03-28 19:25:30 +02001083 int i, j;
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001084 bool rootfs_found;
1085 struct stm32prog_part_t *part;
Patrick Delaunay8dc57682022-03-28 19:25:30 +02001086 const char *type_str;
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001087
1088 buf = malloc(buflen);
1089 if (!buf)
1090 return -ENOMEM;
1091
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001092 /* initialize the selected device */
1093 for (i = 0; i < data->dev_nb; i++) {
Patrick Delaunay5ce50062020-03-18 09:24:53 +01001094 /* create gpt partition support only for full update on MMC */
1095 if (data->dev[i].target != STM32PROG_MMC ||
1096 !data->dev[i].full_update)
1097 continue;
1098
Patrick Delaunay95a6bf42022-09-09 17:22:15 +02001099 printf("partitions on mmc%d: ", data->dev[i].dev_id);
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001100 offset = 0;
1101 rootfs_found = false;
1102 memset(buf, 0, buflen);
1103
1104 list_for_each_entry(part, &data->dev[i].part_list, list) {
Patrick Delaunay6915b492020-03-18 09:24:52 +01001105 /* skip eMMC boot partitions */
1106 if (part->part_id < 0)
1107 continue;
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001108 /* skip Raw Image */
1109 if (part->part_type == RAW_IMAGE)
1110 continue;
1111
1112 if (offset + 100 > buflen) {
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001113 log_debug("\n%s: buffer too small, %s skippped",
1114 __func__, part->name);
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001115 continue;
1116 }
1117
1118 if (!offset)
1119 offset += sprintf(buf, "gpt write mmc %d \"",
1120 data->dev[i].dev_id);
1121
1122 offset += snprintf(buf + offset, buflen - offset,
1123 "name=%s,start=0x%llx,size=0x%llx",
1124 part->name,
1125 part->addr,
1126 part->size);
1127
Patrick Delaunay8dc57682022-03-28 19:25:30 +02001128 switch (part->part_type) {
1129 case PART_BINARY:
1130 type_str = LINUX_RESERVED_UUID;
1131 break;
Patrick Delaunayb386b9c2023-06-08 17:09:54 +02001132 case PART_ENV:
1133 type_str = "u-boot-env";
1134 break;
Patrick Delaunay8dc57682022-03-28 19:25:30 +02001135 case PART_FIP:
1136 type_str = FIP_TYPE_UUID;
1137 break;
Patrick Delaunayc203c212023-06-08 17:09:56 +02001138 case PART_FWU_MDATA:
1139 type_str = FWU_MDATA_UUID;
1140 break;
Patrick Delaunay0e582be2023-06-08 17:09:55 +02001141 case PART_ESP:
1142 /* EFI System Partition */
1143 type_str = "system";
1144 break;
1145 default: /* PART_FILESYSTEM or PART_SYSTEM for distro */
Patrick Delaunay8dc57682022-03-28 19:25:30 +02001146 type_str = "linux";
1147 break;
1148 }
1149 offset += snprintf(buf + offset,
1150 buflen - offset,
1151 ",type=%s", type_str);
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001152
1153 if (part->part_type == PART_SYSTEM)
1154 offset += snprintf(buf + offset,
1155 buflen - offset,
1156 ",bootable");
1157
Patrick Delaunay8dc57682022-03-28 19:25:30 +02001158 /* partition UUID */
1159 uuid_bin = NULL;
Patrick Delaunay2b894292025-01-16 10:54:34 +01001160 if (!rootfs_found && (!strcmp(part->name, "rootfs") ||
1161 !strcmp(part->name, "rootfs-a"))) {
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001162 mmc_id = part->dev_id;
1163 rootfs_found = true;
Patrick Delaunay8dc57682022-03-28 19:25:30 +02001164 if (mmc_id < ARRAY_SIZE(uuid_mmc))
1165 uuid_bin = (unsigned char *)uuid_mmc[mmc_id].b;
1166 }
1167 if (part->part_type == PART_FIP) {
1168 for (j = 0; j < ARRAY_SIZE(fip_part_name); j++)
1169 if (!strcmp(part->name, fip_part_name[j])) {
1170 uuid_bin = (unsigned char *)fip_part_uuid[j].b;
1171 break;
1172 }
1173 }
1174 if (uuid_bin) {
1175 uuid_bin_to_str(uuid_bin, uuid, UUID_STR_FORMAT_GUID);
1176 offset += snprintf(buf + offset,
1177 buflen - offset,
1178 ",uuid=%s", uuid);
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001179 }
1180
1181 offset += snprintf(buf + offset, buflen - offset, ";");
1182 }
1183
1184 if (offset) {
1185 offset += snprintf(buf + offset, buflen - offset, "\"");
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001186 log_debug("\ncmd: %s\n", buf);
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001187 if (run_command(buf, 0)) {
1188 stm32prog_err("GPT partitionning fail: %s",
1189 buf);
1190 free(buf);
1191
1192 return -1;
1193 }
1194 }
1195
1196 if (data->dev[i].mmc)
1197 part_init(mmc_get_blk_desc(data->dev[i].mmc));
1198
1199#ifdef DEBUG
1200 sprintf(buf, "gpt verify mmc %d", data->dev[i].dev_id);
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001201 log_debug("\ncmd: %s", buf);
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001202 if (run_command(buf, 0))
1203 printf("fail !\n");
1204 else
1205 printf("OK\n");
1206
1207 sprintf(buf, "part list mmc %d", data->dev[i].dev_id);
1208 run_command(buf, 0);
1209#endif
Patrick Delaunay95a6bf42022-09-09 17:22:15 +02001210 puts("done\n");
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001211 }
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001212
Patrick Delaunay6ab74962020-03-18 09:24:54 +01001213#ifdef DEBUG
1214 run_command("mtd list", 0);
1215#endif
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001216 free(buf);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001217
1218 return 0;
1219}
1220
1221static int stm32prog_alt_add(struct stm32prog_data *data,
1222 struct dfu_entity *dfu,
1223 struct stm32prog_part_t *part)
1224{
1225 int ret = 0;
1226 int offset = 0;
1227 char devstr[10];
1228 char dfustr[10];
1229 char buf[ALT_BUF_LEN];
1230 u32 size;
1231 char multiplier, type;
1232
1233 /* max 3 digit for sector size */
Patrice Chotard01e58942024-11-29 13:27:08 +01001234 if (part->size > SZ_1G) {
1235 size = (u32)(part->size / SZ_1G);
1236 multiplier = 'G';
1237 } else if (part->size > SZ_1M) {
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001238 size = (u32)(part->size / SZ_1M);
1239 multiplier = 'M';
1240 } else if (part->size > SZ_1K) {
1241 size = (u32)(part->size / SZ_1K);
1242 multiplier = 'K';
1243 } else {
1244 size = (u32)part->size;
1245 multiplier = 'B';
1246 }
1247 if (IS_SELECT(part) && !IS_EMPTY(part))
1248 type = 'e'; /*Readable and Writeable*/
1249 else
1250 type = 'a';/*Readable*/
1251
1252 memset(buf, 0, sizeof(buf));
1253 offset = snprintf(buf, ALT_BUF_LEN - offset,
1254 "@%s/0x%02x/1*%d%c%c ",
1255 part->name, part->id,
1256 size, multiplier, type);
1257
Patrick Delaunay41e6ace2020-03-18 09:25:03 +01001258 if (part->target == STM32PROG_RAM) {
1259 offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
1260 "ram 0x%llx 0x%llx",
1261 part->addr, part->size);
1262 } else if (part->part_type == RAW_IMAGE) {
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001263 u64 dfu_size;
1264
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001265 if (part->dev->target == STM32PROG_MMC)
1266 dfu_size = part->size / part->dev->mmc->read_bl_len;
1267 else
1268 dfu_size = part->size;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001269 offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
1270 "raw 0x0 0x%llx", dfu_size);
Patrick Delaunay6915b492020-03-18 09:24:52 +01001271 } else if (part->part_id < 0) {
1272 u64 nb_blk = part->size / part->dev->mmc->read_bl_len;
1273
1274 offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
1275 "raw 0x%llx 0x%llx",
1276 part->addr, nb_blk);
1277 offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
Patrick Delaunayb5793a62022-06-16 18:37:59 +02001278 " mmcpart %d", -(part->part_id));
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001279 } else {
Patrick Delaunay6ab74962020-03-18 09:24:54 +01001280 if (part->part_type == PART_SYSTEM &&
1281 (part->target == STM32PROG_NAND ||
1282 part->target == STM32PROG_NOR ||
1283 part->target == STM32PROG_SPI_NAND))
1284 offset += snprintf(buf + offset,
1285 ALT_BUF_LEN - offset,
1286 "partubi");
1287 else
1288 offset += snprintf(buf + offset,
1289 ALT_BUF_LEN - offset,
1290 "part");
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001291 /* dev_id requested by DFU MMC */
1292 if (part->target == STM32PROG_MMC)
1293 offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
1294 " %d", part->dev_id);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001295 offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
Patrick Delaunayb5793a62022-06-16 18:37:59 +02001296 " %d", part->part_id);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001297 }
Patrick Delaunay8040da12020-07-31 16:31:52 +02001298 ret = -ENODEV;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001299 switch (part->target) {
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001300 case STM32PROG_MMC:
Patrick Delaunay8040da12020-07-31 16:31:52 +02001301 if (IS_ENABLED(CONFIG_MMC)) {
1302 ret = 0;
1303 sprintf(dfustr, "mmc");
1304 sprintf(devstr, "%d", part->dev_id);
1305 }
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001306 break;
Patrick Delaunay6ab74962020-03-18 09:24:54 +01001307 case STM32PROG_NAND:
1308 case STM32PROG_NOR:
1309 case STM32PROG_SPI_NAND:
Patrick Delaunay8040da12020-07-31 16:31:52 +02001310 if (IS_ENABLED(CONFIG_MTD)) {
1311 ret = 0;
1312 sprintf(dfustr, "mtd");
1313 get_mtd_by_target(devstr, part->target, part->dev_id);
1314 }
Patrick Delaunay6ab74962020-03-18 09:24:54 +01001315 break;
Patrick Delaunay41e6ace2020-03-18 09:25:03 +01001316 case STM32PROG_RAM:
Patrick Delaunay8040da12020-07-31 16:31:52 +02001317 ret = 0;
Patrick Delaunay41e6ace2020-03-18 09:25:03 +01001318 sprintf(dfustr, "ram");
1319 sprintf(devstr, "0");
1320 break;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001321 default:
Patrick Delaunay8040da12020-07-31 16:31:52 +02001322 break;
1323 }
1324 if (ret) {
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001325 stm32prog_err("invalid target: %d", part->target);
Patrick Delaunay8040da12020-07-31 16:31:52 +02001326 return ret;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001327 }
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001328 log_debug("dfu_alt_add(%s,%s,%s)\n", dfustr, devstr, buf);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001329 ret = dfu_alt_add(dfu, dfustr, devstr, buf);
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001330 log_debug("dfu_alt_add(%s,%s,%s) result %d\n",
1331 dfustr, devstr, buf, ret);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001332
1333 return ret;
1334}
1335
1336static int stm32prog_alt_add_virt(struct dfu_entity *dfu,
1337 char *name, int phase, int size)
1338{
1339 int ret = 0;
1340 char devstr[4];
1341 char buf[ALT_BUF_LEN];
1342
1343 sprintf(devstr, "%d", phase);
1344 sprintf(buf, "@%s/0x%02x/1*%dBe", name, phase, size);
1345 ret = dfu_alt_add(dfu, "virt", devstr, buf);
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001346 log_debug("dfu_alt_add(virt,%s,%s) result %d\n", devstr, buf, ret);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001347
1348 return ret;
1349}
1350
1351static int dfu_init_entities(struct stm32prog_data *data)
1352{
1353 int ret = 0;
1354 int phase, i, alt_id;
1355 struct stm32prog_part_t *part;
1356 struct dfu_entity *dfu;
1357 int alt_nb;
Patrick Delaunay9a699b72022-09-06 18:53:20 +02001358 u32 otp_size = 0;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001359
Patrick Delaunay455b06a2022-03-28 19:25:27 +02001360 alt_nb = 1; /* number of virtual = CMD*/
Patrick Delaunay9a699b72022-09-06 18:53:20 +02001361
Patrick Delaunay285025f2024-03-20 15:56:42 +01001362 if (IS_ENABLED(CONFIG_CMD_STM32PROG_OTP) && !stm32mp_is_closed()) {
Patrick Delaunay9a699b72022-09-06 18:53:20 +02001363 /* OTP_SIZE_SMC = 0 if SMC is not supported */
1364 otp_size = OTP_SIZE_SMC;
1365 /* check if PTA BSEC is supported */
1366 ret = optee_ta_open(data);
1367 log_debug("optee_ta_open(PTA_NVMEM) result %d\n", ret);
1368 if (!ret && data->tee)
1369 otp_size = OTP_SIZE_TA;
1370 if (otp_size)
1371 alt_nb++; /* OTP*/
1372 }
1373
Patrick Delaunay7d145402021-05-18 15:12:09 +02001374 if (CONFIG_IS_ENABLED(DM_PMIC))
1375 alt_nb++; /* PMIC NVMEM*/
1376
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001377 if (data->part_nb == 0)
1378 alt_nb++; /* +1 for FlashLayout */
1379 else
1380 for (i = 0; i < data->part_nb; i++) {
1381 if (data->part_array[i].target != STM32PROG_NONE)
1382 alt_nb++;
1383 }
1384
1385 if (dfu_alt_init(alt_nb, &dfu))
1386 return -ENODEV;
1387
1388 puts("DFU alt info setting: ");
1389 if (data->part_nb) {
1390 alt_id = 0;
Patrick Delaunay9a699b72022-09-06 18:53:20 +02001391 ret = 0;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001392 for (phase = 1;
1393 (phase <= PHASE_LAST_USER) &&
1394 (alt_id < alt_nb) && !ret;
1395 phase++) {
1396 /* ordering alt setting by phase id */
1397 part = NULL;
1398 for (i = 0; i < data->part_nb; i++) {
1399 if (phase == data->part_array[i].id) {
1400 part = &data->part_array[i];
1401 break;
1402 }
1403 }
1404 if (!part)
1405 continue;
1406 if (part->target == STM32PROG_NONE)
1407 continue;
1408 part->alt_id = alt_id;
1409 alt_id++;
1410
1411 ret = stm32prog_alt_add(data, dfu, part);
1412 }
1413 } else {
1414 char buf[ALT_BUF_LEN];
1415
1416 sprintf(buf, "@FlashLayout/0x%02x/1*256Ke ram %x 40000",
Patrick Delaunaye334d322022-09-06 18:53:18 +02001417 PHASE_FLASHLAYOUT, CONFIG_SYS_LOAD_ADDR);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001418 ret = dfu_alt_add(dfu, "ram", NULL, buf);
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001419 log_debug("dfu_alt_add(ram, NULL,%s) result %d\n", buf, ret);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001420 }
1421
1422 if (!ret)
Patrick Delaunaybd577492021-07-05 09:39:01 +02001423 ret = stm32prog_alt_add_virt(dfu, "virtual", PHASE_CMD, CMD_SIZE);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001424
Patrick Delaunay9a699b72022-09-06 18:53:20 +02001425 if (!ret && IS_ENABLED(CONFIG_CMD_STM32PROG_OTP) && otp_size)
1426 ret = stm32prog_alt_add_virt(dfu, "OTP", PHASE_OTP, otp_size);
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001427
Patrick Delaunay541c7de2020-03-18 09:24:59 +01001428 if (!ret && CONFIG_IS_ENABLED(DM_PMIC))
Patrick Delaunaybd577492021-07-05 09:39:01 +02001429 ret = stm32prog_alt_add_virt(dfu, "PMIC", PHASE_PMIC, PMIC_SIZE);
Patrick Delaunay541c7de2020-03-18 09:24:59 +01001430
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001431 if (ret)
1432 stm32prog_err("dfu init failed: %d", ret);
1433 puts("done\n");
1434
1435#ifdef DEBUG
1436 dfu_show_entities();
1437#endif
1438 return ret;
1439}
1440
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001441int stm32prog_otp_write(struct stm32prog_data *data, u32 offset, u8 *buffer,
1442 long *size)
1443{
Patrick Delaunay8da5df92022-03-28 19:25:28 +02001444 u32 otp_size = data->tee ? OTP_SIZE_TA : OTP_SIZE_SMC;
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001445 log_debug("%s: %x %lx\n", __func__, offset, *size);
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001446
Patrick Delaunay455b06a2022-03-28 19:25:27 +02001447 if (!IS_ENABLED(CONFIG_CMD_STM32PROG_OTP)) {
1448 stm32prog_err("OTP update not supported");
1449
1450 return -EOPNOTSUPP;
1451 }
Patrick Delaunay8da5df92022-03-28 19:25:28 +02001452
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001453 if (!data->otp_part) {
Patrick Delaunay8da5df92022-03-28 19:25:28 +02001454 data->otp_part = memalign(CONFIG_SYS_CACHELINE_SIZE, otp_size);
Patrick Delaunay9e1dba32023-04-27 15:36:36 +02001455 if (!data->otp_part) {
1456 stm32prog_err("OTP write issue %d", -ENOMEM);
1457
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001458 return -ENOMEM;
Patrick Delaunay9e1dba32023-04-27 15:36:36 +02001459 }
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001460 }
1461
1462 if (!offset)
Patrick Delaunay8da5df92022-03-28 19:25:28 +02001463 memset(data->otp_part, 0, otp_size);
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001464
Patrick Delaunay8da5df92022-03-28 19:25:28 +02001465 if (offset + *size > otp_size)
1466 *size = otp_size - offset;
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001467
Patrick Delaunay21ea4ef2022-09-06 18:53:19 +02001468 memcpy((void *)((uintptr_t)data->otp_part + offset), buffer, *size);
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001469
1470 return 0;
1471}
1472
1473int stm32prog_otp_read(struct stm32prog_data *data, u32 offset, u8 *buffer,
1474 long *size)
1475{
Patrick Delaunay8da5df92022-03-28 19:25:28 +02001476 u32 otp_size = data->tee ? OTP_SIZE_TA : OTP_SIZE_SMC;
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001477 int result = 0;
1478
Patrick Delaunay455b06a2022-03-28 19:25:27 +02001479 if (!IS_ENABLED(CONFIG_CMD_STM32PROG_OTP)) {
Patrick Delaunay8040da12020-07-31 16:31:52 +02001480 stm32prog_err("OTP update not supported");
1481
Patrick Delaunay455b06a2022-03-28 19:25:27 +02001482 return -EOPNOTSUPP;
Patrick Delaunay8040da12020-07-31 16:31:52 +02001483 }
1484
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001485 log_debug("%s: %x %lx\n", __func__, offset, *size);
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001486 /* alway read for first packet */
1487 if (!offset) {
1488 if (!data->otp_part)
1489 data->otp_part =
Patrick Delaunay8da5df92022-03-28 19:25:28 +02001490 memalign(CONFIG_SYS_CACHELINE_SIZE, otp_size);
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001491
1492 if (!data->otp_part) {
1493 result = -ENOMEM;
1494 goto end_otp_read;
1495 }
1496
1497 /* init struct with 0 */
Patrick Delaunay8da5df92022-03-28 19:25:28 +02001498 memset(data->otp_part, 0, otp_size);
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001499
1500 /* call the service */
Patrick Delaunay455b06a2022-03-28 19:25:27 +02001501 result = -EOPNOTSUPP;
Patrick Delaunay8da5df92022-03-28 19:25:28 +02001502 if (data->tee && CONFIG_IS_ENABLED(OPTEE))
1503 result = optee_ta_invoke(data, TA_NVMEM_READ, NVMEM_OTP,
1504 data->otp_part, OTP_SIZE_TA);
1505 else if (IS_ENABLED(CONFIG_ARM_SMCCC))
Patrick Delaunay455b06a2022-03-28 19:25:27 +02001506 result = stm32_smc_exec(STM32_SMC_BSEC, STM32_SMC_READ_ALL,
Patrick Delaunay21ea4ef2022-09-06 18:53:19 +02001507 (unsigned long)data->otp_part, 0);
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001508 if (result)
1509 goto end_otp_read;
1510 }
1511
1512 if (!data->otp_part) {
1513 result = -ENOMEM;
1514 goto end_otp_read;
1515 }
1516
Patrick Delaunay8da5df92022-03-28 19:25:28 +02001517 if (offset + *size > otp_size)
1518 *size = otp_size - offset;
Patrick Delaunay21ea4ef2022-09-06 18:53:19 +02001519 memcpy(buffer, (void *)((uintptr_t)data->otp_part + offset), *size);
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001520
1521end_otp_read:
Patrick Delaunay9e1dba32023-04-27 15:36:36 +02001522 if (result)
1523 stm32prog_err("OTP read issue %d", result);
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001524 log_debug("%s: result %i\n", __func__, result);
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001525
1526 return result;
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001527}
1528
1529int stm32prog_otp_start(struct stm32prog_data *data)
1530{
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001531 int result = 0;
1532 struct arm_smccc_res res;
1533
Patrick Delaunay455b06a2022-03-28 19:25:27 +02001534 if (!IS_ENABLED(CONFIG_CMD_STM32PROG_OTP)) {
Patrick Delaunay8040da12020-07-31 16:31:52 +02001535 stm32prog_err("OTP update not supported");
1536
Patrick Delaunay455b06a2022-03-28 19:25:27 +02001537 return -EOPNOTSUPP;
Patrick Delaunay8040da12020-07-31 16:31:52 +02001538 }
1539
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001540 if (!data->otp_part) {
1541 stm32prog_err("start OTP without data");
1542 return -1;
1543 }
1544
Patrick Delaunay455b06a2022-03-28 19:25:27 +02001545 result = -EOPNOTSUPP;
Patrick Delaunay8da5df92022-03-28 19:25:28 +02001546 if (data->tee && CONFIG_IS_ENABLED(OPTEE)) {
1547 result = optee_ta_invoke(data, TA_NVMEM_WRITE, NVMEM_OTP,
1548 data->otp_part, OTP_SIZE_TA);
1549 } else if (IS_ENABLED(CONFIG_ARM_SMCCC)) {
Patrick Delaunay455b06a2022-03-28 19:25:27 +02001550 arm_smccc_smc(STM32_SMC_BSEC, STM32_SMC_WRITE_ALL,
Patrick Delaunay21ea4ef2022-09-06 18:53:19 +02001551 (uintptr_t)data->otp_part, 0, 0, 0, 0, 0, &res);
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001552
Patrick Delaunay455b06a2022-03-28 19:25:27 +02001553 if (!res.a0) {
1554 switch (res.a1) {
1555 case 0:
1556 result = 0;
1557 break;
1558 case 1:
1559 stm32prog_err("Provisioning");
1560 result = 0;
1561 break;
1562 default:
1563 log_err("%s: OTP incorrect value (err = %ld)\n",
1564 __func__, res.a1);
1565 result = -EINVAL;
1566 break;
1567 }
1568 } else {
1569 log_err("%s: Failed to exec svc=%x op=%x in secure mode (err = %ld)\n",
1570 __func__, STM32_SMC_BSEC, STM32_SMC_WRITE_ALL, res.a0);
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001571 result = -EINVAL;
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001572 }
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001573 }
1574
1575 free(data->otp_part);
1576 data->otp_part = NULL;
Patrick Delaunay9e1dba32023-04-27 15:36:36 +02001577 if (result)
1578 stm32prog_err("OTP write issue %d", result);
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001579 log_debug("%s: result %i\n", __func__, result);
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001580
1581 return result;
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001582}
1583
Patrick Delaunay541c7de2020-03-18 09:24:59 +01001584int stm32prog_pmic_write(struct stm32prog_data *data, u32 offset, u8 *buffer,
1585 long *size)
1586{
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001587 log_debug("%s: %x %lx\n", __func__, offset, *size);
Patrick Delaunay541c7de2020-03-18 09:24:59 +01001588
1589 if (!offset)
1590 memset(data->pmic_part, 0, PMIC_SIZE);
1591
1592 if (offset + *size > PMIC_SIZE)
1593 *size = PMIC_SIZE - offset;
1594
1595 memcpy(&data->pmic_part[offset], buffer, *size);
1596
1597 return 0;
1598}
1599
1600int stm32prog_pmic_read(struct stm32prog_data *data, u32 offset, u8 *buffer,
1601 long *size)
1602{
1603 int result = 0, ret;
1604 struct udevice *dev;
1605
Simon Glassb24d5752023-02-05 15:40:35 -07001606 if (!IS_ENABLED(CONFIG_PMIC_STPMIC1)) {
Patrick Delaunay541c7de2020-03-18 09:24:59 +01001607 stm32prog_err("PMIC update not supported");
1608
1609 return -EOPNOTSUPP;
1610 }
1611
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001612 log_debug("%s: %x %lx\n", __func__, offset, *size);
Patrick Delaunay541c7de2020-03-18 09:24:59 +01001613 ret = uclass_get_device_by_driver(UCLASS_MISC,
Simon Glass65130cd2020-12-28 20:34:56 -07001614 DM_DRIVER_GET(stpmic1_nvm),
Patrick Delaunay541c7de2020-03-18 09:24:59 +01001615 &dev);
1616 if (ret)
1617 return ret;
1618
1619 /* alway request PMIC for first packet */
1620 if (!offset) {
1621 /* init struct with 0 */
1622 memset(data->pmic_part, 0, PMIC_SIZE);
1623
1624 ret = uclass_get_device_by_driver(UCLASS_MISC,
Simon Glass65130cd2020-12-28 20:34:56 -07001625 DM_DRIVER_GET(stpmic1_nvm),
Patrick Delaunay541c7de2020-03-18 09:24:59 +01001626 &dev);
1627 if (ret)
1628 return ret;
1629
1630 ret = misc_read(dev, 0xF8, data->pmic_part, PMIC_SIZE);
1631 if (ret < 0) {
1632 result = ret;
1633 goto end_pmic_read;
1634 }
1635 if (ret != PMIC_SIZE) {
1636 result = -EACCES;
1637 goto end_pmic_read;
1638 }
1639 }
1640
1641 if (offset + *size > PMIC_SIZE)
1642 *size = PMIC_SIZE - offset;
1643
1644 memcpy(buffer, &data->pmic_part[offset], *size);
1645
1646end_pmic_read:
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001647 log_debug("%s: result %i\n", __func__, result);
Patrick Delaunay541c7de2020-03-18 09:24:59 +01001648 return result;
1649}
1650
1651int stm32prog_pmic_start(struct stm32prog_data *data)
1652{
1653 int ret;
1654 struct udevice *dev;
1655
Simon Glassb24d5752023-02-05 15:40:35 -07001656 if (!IS_ENABLED(CONFIG_PMIC_STPMIC1)) {
Patrick Delaunay541c7de2020-03-18 09:24:59 +01001657 stm32prog_err("PMIC update not supported");
1658
1659 return -EOPNOTSUPP;
1660 }
1661
1662 ret = uclass_get_device_by_driver(UCLASS_MISC,
Simon Glass65130cd2020-12-28 20:34:56 -07001663 DM_DRIVER_GET(stpmic1_nvm),
Patrick Delaunay541c7de2020-03-18 09:24:59 +01001664 &dev);
1665 if (ret)
1666 return ret;
1667
1668 return misc_write(dev, 0xF8, data->pmic_part, PMIC_SIZE);
1669}
1670
Patrick Delaunay851d6f32020-03-18 09:24:56 +01001671/* copy FSBL on NAND to improve reliability on NAND */
1672static int stm32prog_copy_fsbl(struct stm32prog_part_t *part)
1673{
1674 int ret, i;
1675 void *fsbl;
1676 struct image_header_s header;
Patrick Delaunay953d8bf2022-03-28 19:25:29 +02001677 struct stm32_header_v2 raw_header; /* V2 size > v1 size */
Patrick Delaunay851d6f32020-03-18 09:24:56 +01001678 struct dfu_entity *dfu;
1679 long size, offset;
1680
1681 if (part->target != STM32PROG_NAND &&
1682 part->target != STM32PROG_SPI_NAND)
Patrick Delaunay19676ef2021-04-02 14:05:17 +02001683 return -EINVAL;
Patrick Delaunay851d6f32020-03-18 09:24:56 +01001684
1685 dfu = dfu_get_entity(part->alt_id);
1686
1687 /* read header */
1688 dfu_transaction_cleanup(dfu);
Patrick Delaunay953d8bf2022-03-28 19:25:29 +02001689 size = sizeof(raw_header);
Patrick Delaunay851d6f32020-03-18 09:24:56 +01001690 ret = dfu->read_medium(dfu, 0, (void *)&raw_header, &size);
1691 if (ret)
1692 return ret;
Patrick Delaunay19676ef2021-04-02 14:05:17 +02001693
Patrick Delaunay953d8bf2022-03-28 19:25:29 +02001694 stm32prog_header_check((ulong)&raw_header, &header);
1695 if (header.type != HEADER_STM32IMAGE &&
1696 header.type != HEADER_STM32IMAGE_V2)
Patrick Delaunay19676ef2021-04-02 14:05:17 +02001697 return -ENOENT;
Patrick Delaunay851d6f32020-03-18 09:24:56 +01001698
1699 /* read header + payload */
Patrick Delaunay953d8bf2022-03-28 19:25:29 +02001700 size = header.image_length + header.length;
Patrick Delaunay851d6f32020-03-18 09:24:56 +01001701 size = round_up(size, part->dev->mtd->erasesize);
1702 fsbl = calloc(1, size);
1703 if (!fsbl)
1704 return -ENOMEM;
1705 ret = dfu->read_medium(dfu, 0, fsbl, &size);
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001706 log_debug("%s read size=%lx ret=%d\n", __func__, size, ret);
Patrick Delaunay851d6f32020-03-18 09:24:56 +01001707 if (ret)
1708 goto error;
1709
1710 dfu_transaction_cleanup(dfu);
1711 offset = 0;
1712 for (i = part->bin_nb - 1; i > 0; i--) {
1713 offset += size;
1714 /* write to the next erase block */
1715 ret = dfu->write_medium(dfu, offset, fsbl, &size);
Patrick Delaunay2b15af52020-11-06 19:01:30 +01001716 log_debug("%s copy at ofset=%lx size=%lx ret=%d",
1717 __func__, offset, size, ret);
Patrick Delaunay851d6f32020-03-18 09:24:56 +01001718 if (ret)
1719 goto error;
1720 }
1721
1722error:
1723 free(fsbl);
1724 return ret;
1725}
1726
Patrick Delaunayab198fe2021-05-18 15:12:06 +02001727static void stm32prog_end_phase(struct stm32prog_data *data, u64 offset)
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001728{
1729 if (data->phase == PHASE_FLASHLAYOUT) {
Patrick Delaunayb9ef46b2022-03-28 19:25:32 +02001730#if defined(CONFIG_LEGACY_IMAGE_FORMAT)
Patrick Delaunaye334d322022-09-06 18:53:18 +02001731 if (genimg_get_format((void *)CONFIG_SYS_LOAD_ADDR) == IMAGE_FORMAT_LEGACY) {
1732 data->script = CONFIG_SYS_LOAD_ADDR;
Patrick Delaunayb9ef46b2022-03-28 19:25:32 +02001733 data->phase = PHASE_END;
1734 log_notice("U-Boot script received\n");
1735 return;
1736 }
1737#endif
Patrick Delaunayc14b0eb2022-03-28 19:25:33 +02001738 log_notice("\nFlashLayout received, size = %lld\n", offset);
Patrick Delaunaye334d322022-09-06 18:53:18 +02001739 if (parse_flash_layout(data, CONFIG_SYS_LOAD_ADDR, offset))
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001740 stm32prog_err("Layout: invalid FlashLayout");
1741 return;
1742 }
1743
1744 if (!data->cur_part)
1745 return;
Patrick Delaunay6915b492020-03-18 09:24:52 +01001746
Patrick Delaunay41e6ace2020-03-18 09:25:03 +01001747 if (data->cur_part->target == STM32PROG_RAM) {
1748 if (data->cur_part->part_type == PART_SYSTEM)
1749 data->uimage = data->cur_part->addr;
1750 if (data->cur_part->part_type == PART_FILESYSTEM)
1751 data->dtb = data->cur_part->addr;
Patrick Delaunayab198fe2021-05-18 15:12:06 +02001752 if (data->cur_part->part_type == PART_BINARY) {
1753 data->initrd = data->cur_part->addr;
1754 data->initrd_size = offset;
1755 }
Patrick Delaunay41e6ace2020-03-18 09:25:03 +01001756 }
1757
Patrick Delaunay6915b492020-03-18 09:24:52 +01001758 if (CONFIG_IS_ENABLED(MMC) &&
1759 data->cur_part->part_id < 0) {
1760 char cmdbuf[60];
1761
1762 sprintf(cmdbuf, "mmc bootbus %d 0 0 0; mmc partconf %d 1 %d 0",
1763 data->cur_part->dev_id, data->cur_part->dev_id,
1764 -(data->cur_part->part_id));
1765 if (run_command(cmdbuf, 0)) {
1766 stm32prog_err("commands '%s' failed", cmdbuf);
1767 return;
1768 }
1769 }
Patrick Delaunay851d6f32020-03-18 09:24:56 +01001770
Simon Glass8e05bb12023-02-05 15:40:17 -07001771 if (IS_ENABLED(CONFIG_MTD) &&
Patrick Delaunay851d6f32020-03-18 09:24:56 +01001772 data->cur_part->bin_nb > 1) {
1773 if (stm32prog_copy_fsbl(data->cur_part)) {
1774 stm32prog_err("%s (0x%x): copy of fsbl failed",
1775 data->cur_part->name, data->cur_part->id);
1776 return;
1777 }
1778 }
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001779}
1780
1781void stm32prog_do_reset(struct stm32prog_data *data)
1782{
1783 if (data->phase == PHASE_RESET) {
1784 data->phase = PHASE_DO_RESET;
1785 puts("Reset requested\n");
1786 }
1787}
1788
1789void stm32prog_next_phase(struct stm32prog_data *data)
1790{
1791 int phase, i;
1792 struct stm32prog_part_t *part;
1793 bool found;
1794
1795 phase = data->phase;
1796 switch (phase) {
1797 case PHASE_RESET:
1798 case PHASE_END:
1799 case PHASE_DO_RESET:
1800 return;
1801 }
1802
1803 /* found next selected partition */
Patrick Delaunayb823d992020-03-18 09:25:00 +01001804 data->dfu_seq = 0;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001805 data->cur_part = NULL;
1806 data->phase = PHASE_END;
1807 found = false;
1808 do {
1809 phase++;
1810 if (phase > PHASE_LAST_USER)
1811 break;
1812 for (i = 0; i < data->part_nb; i++) {
1813 part = &data->part_array[i];
1814 if (part->id == phase) {
1815 if (IS_SELECT(part) && !IS_EMPTY(part)) {
1816 data->cur_part = part;
1817 data->phase = phase;
1818 found = true;
1819 }
1820 break;
1821 }
1822 }
1823 } while (!found);
1824
1825 if (data->phase == PHASE_END)
1826 puts("Phase=END\n");
1827}
1828
Patrick Delaunay291e7222020-03-18 09:24:57 +01001829static int part_delete(struct stm32prog_data *data,
1830 struct stm32prog_part_t *part)
1831{
1832 int ret = 0;
Patrick Delaunay291e7222020-03-18 09:24:57 +01001833 unsigned long blks, blks_offset, blks_size;
1834 struct blk_desc *block_dev = NULL;
Patrick Delaunay291e7222020-03-18 09:24:57 +01001835 char cmdbuf[40];
1836 char devstr[10];
Patrick Delaunay291e7222020-03-18 09:24:57 +01001837
1838 printf("Erasing %s ", part->name);
1839 switch (part->target) {
Patrick Delaunay291e7222020-03-18 09:24:57 +01001840 case STM32PROG_MMC:
Patrick Delaunay8040da12020-07-31 16:31:52 +02001841 if (!IS_ENABLED(CONFIG_MMC)) {
1842 ret = -1;
1843 stm32prog_err("%s (0x%x): erase invalid",
1844 part->name, part->id);
1845 break;
1846 }
Patrick Delaunay291e7222020-03-18 09:24:57 +01001847 printf("on mmc %d: ", part->dev->dev_id);
1848 block_dev = mmc_get_blk_desc(part->dev->mmc);
1849 blks_offset = lldiv(part->addr, part->dev->mmc->read_bl_len);
1850 blks_size = lldiv(part->size, part->dev->mmc->read_bl_len);
1851 /* -1 or -2 : delete boot partition of MMC
1852 * need to switch to associated hwpart 1 or 2
1853 */
1854 if (part->part_id < 0)
Simon Glassdbfa32c2022-08-11 19:34:59 -06001855 if (blk_select_hwpart_devnum(UCLASS_MMC,
Patrick Delaunay291e7222020-03-18 09:24:57 +01001856 part->dev->dev_id,
1857 -part->part_id))
1858 return -1;
1859
1860 blks = blk_derase(block_dev, blks_offset, blks_size);
1861
1862 /* return to user partition */
1863 if (part->part_id < 0)
Simon Glassdbfa32c2022-08-11 19:34:59 -06001864 blk_select_hwpart_devnum(UCLASS_MMC,
Patrick Delaunay291e7222020-03-18 09:24:57 +01001865 part->dev->dev_id, 0);
1866 if (blks != blks_size) {
1867 ret = -1;
1868 stm32prog_err("%s (0x%x): MMC erase failed",
1869 part->name, part->id);
1870 }
1871 break;
Patrick Delaunay291e7222020-03-18 09:24:57 +01001872 case STM32PROG_NOR:
1873 case STM32PROG_NAND:
1874 case STM32PROG_SPI_NAND:
Patrick Delaunay8040da12020-07-31 16:31:52 +02001875 if (!IS_ENABLED(CONFIG_MTD)) {
1876 ret = -1;
1877 stm32prog_err("%s (0x%x): erase invalid",
1878 part->name, part->id);
1879 break;
1880 }
Patrick Delaunay291e7222020-03-18 09:24:57 +01001881 get_mtd_by_target(devstr, part->target, part->dev->dev_id);
1882 printf("on %s: ", devstr);
1883 sprintf(cmdbuf, "mtd erase %s 0x%llx 0x%llx",
1884 devstr, part->addr, part->size);
1885 if (run_command(cmdbuf, 0)) {
1886 ret = -1;
1887 stm32prog_err("%s (0x%x): MTD erase commands failed (%s)",
1888 part->name, part->id, cmdbuf);
1889 }
1890 break;
Patrick Delaunay41e6ace2020-03-18 09:25:03 +01001891 case STM32PROG_RAM:
1892 printf("on ram: ");
1893 memset((void *)(uintptr_t)part->addr, 0, (size_t)part->size);
1894 break;
Patrick Delaunay291e7222020-03-18 09:24:57 +01001895 default:
1896 ret = -1;
1897 stm32prog_err("%s (0x%x): erase invalid", part->name, part->id);
1898 break;
1899 }
1900 if (!ret)
1901 printf("done\n");
1902
1903 return ret;
1904}
1905
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001906static void stm32prog_devices_init(struct stm32prog_data *data)
1907{
1908 int i;
1909 int ret;
Patrick Delaunay291e7222020-03-18 09:24:57 +01001910 struct stm32prog_part_t *part;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001911
1912 ret = treat_partition_list(data);
1913 if (ret)
1914 goto error;
1915
Patrick Delaunay8f7eb3e2022-09-06 18:53:17 +02001916 /* empty flashlayout */
1917 if (!data->dev_nb)
1918 return;
1919
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001920 /* initialize the selected device */
1921 for (i = 0; i < data->dev_nb; i++) {
1922 ret = init_device(data, &data->dev[i]);
1923 if (ret)
1924 goto error;
1925 }
1926
Patrick Delaunay291e7222020-03-18 09:24:57 +01001927 /* delete RAW partition before create partition */
1928 for (i = 0; i < data->part_nb; i++) {
1929 part = &data->part_array[i];
1930
1931 if (part->part_type != RAW_IMAGE)
1932 continue;
1933
1934 if (!IS_SELECT(part) || !IS_DELETE(part))
1935 continue;
1936
1937 ret = part_delete(data, part);
1938 if (ret)
1939 goto error;
1940 }
1941
Patrick Delaunay8040da12020-07-31 16:31:52 +02001942 if (IS_ENABLED(CONFIG_MMC)) {
1943 ret = create_gpt_partitions(data);
1944 if (ret)
1945 goto error;
1946 }
Patrick Delaunay7aae1e32020-03-18 09:24:51 +01001947
Patrick Delaunay291e7222020-03-18 09:24:57 +01001948 /* delete partition GPT or MTD */
1949 for (i = 0; i < data->part_nb; i++) {
1950 part = &data->part_array[i];
1951
1952 if (part->part_type == RAW_IMAGE)
1953 continue;
1954
1955 if (!IS_SELECT(part) || !IS_DELETE(part))
1956 continue;
1957
1958 ret = part_delete(data, part);
1959 if (ret)
1960 goto error;
1961 }
1962
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001963 return;
1964
1965error:
1966 data->part_nb = 0;
1967}
1968
1969int stm32prog_dfu_init(struct stm32prog_data *data)
1970{
1971 /* init device if no error */
1972 if (data->part_nb)
1973 stm32prog_devices_init(data);
1974
1975 if (data->part_nb)
1976 stm32prog_next_phase(data);
1977
1978 /* prepare DFU for device read/write */
1979 dfu_free_entities();
1980 return dfu_init_entities(data);
1981}
1982
Patrick Delaunay21ea4ef2022-09-06 18:53:19 +02001983int stm32prog_init(struct stm32prog_data *data, uintptr_t addr, ulong size)
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001984{
1985 memset(data, 0x0, sizeof(*data));
Patrick Delaunayb823d992020-03-18 09:25:00 +01001986 data->read_phase = PHASE_RESET;
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01001987 data->phase = PHASE_FLASHLAYOUT;
1988
1989 return parse_flash_layout(data, addr, size);
1990}
1991
1992void stm32prog_clean(struct stm32prog_data *data)
1993{
1994 /* clean */
1995 dfu_free_entities();
1996 free(data->part_array);
Patrick Delaunay1d96b182020-03-18 09:24:58 +01001997 free(data->otp_part);
Patrick Delaunayb823d992020-03-18 09:25:00 +01001998 free(data->buffer);
Patrick Delaunay8da5df92022-03-28 19:25:28 +02001999
2000 if (CONFIG_IS_ENABLED(OPTEE) && data->tee) {
2001 tee_close_session(data->tee, data->tee_session);
2002 data->tee = NULL;
2003 data->tee_session = 0x0;
2004 }
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01002005}
2006
2007/* DFU callback: used after serial and direct DFU USB access */
2008void dfu_flush_callback(struct dfu_entity *dfu)
2009{
2010 if (!stm32prog_data)
2011 return;
2012
Patrick Delaunay1d96b182020-03-18 09:24:58 +01002013 if (dfu->dev_type == DFU_DEV_VIRT) {
2014 if (dfu->data.virt.dev_num == PHASE_OTP)
2015 stm32prog_otp_start(stm32prog_data);
Patrick Delaunay541c7de2020-03-18 09:24:59 +01002016 else if (dfu->data.virt.dev_num == PHASE_PMIC)
2017 stm32prog_pmic_start(stm32prog_data);
Patrick Delaunay1d96b182020-03-18 09:24:58 +01002018 return;
2019 }
2020
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01002021 if (dfu->dev_type == DFU_DEV_RAM) {
2022 if (dfu->alt == 0 &&
2023 stm32prog_data->phase == PHASE_FLASHLAYOUT) {
Patrick Delaunayab198fe2021-05-18 15:12:06 +02002024 stm32prog_end_phase(stm32prog_data, dfu->offset);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01002025 /* waiting DFU DETACH for reenumeration */
2026 }
2027 }
2028
2029 if (!stm32prog_data->cur_part)
2030 return;
2031
2032 if (dfu->alt == stm32prog_data->cur_part->alt_id) {
Patrick Delaunayab198fe2021-05-18 15:12:06 +02002033 stm32prog_end_phase(stm32prog_data, dfu->offset);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01002034 stm32prog_next_phase(stm32prog_data);
2035 }
2036}
2037
2038void dfu_initiated_callback(struct dfu_entity *dfu)
2039{
2040 if (!stm32prog_data)
2041 return;
2042
2043 if (!stm32prog_data->cur_part)
2044 return;
2045
2046 /* force the saved offset for the current partition */
2047 if (dfu->alt == stm32prog_data->cur_part->alt_id) {
2048 dfu->offset = stm32prog_data->offset;
Patrick Delaunayb823d992020-03-18 09:25:00 +01002049 stm32prog_data->dfu_seq = 0;
Patrick Delaunay2b15af52020-11-06 19:01:30 +01002050 log_debug("dfu offset = 0x%llx\n", dfu->offset);
Patrick Delaunay7daa91d2020-03-18 09:24:49 +01002051 }
2052}
Patrick Delaunayc7e9a112021-05-18 15:12:13 +02002053
2054void dfu_error_callback(struct dfu_entity *dfu, const char *msg)
2055{
2056 struct stm32prog_data *data = stm32prog_data;
2057
2058 if (!stm32prog_data)
2059 return;
2060
2061 if (!stm32prog_data->cur_part)
2062 return;
2063
2064 if (dfu->alt == stm32prog_data->cur_part->alt_id)
2065 stm32prog_err(msg);
2066}