1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2023 Linus Walleij <linus.walleij@linaro.org>
4 * Support for the "SEAttle iMAge" SEAMA NAND image format
12 * All SEAMA data is stored in the flash in "network endianness"
13 * i.e. big endian, which means that it needs to be byte-swapped
14 * on all little endian platforms.
16 * structure for a SEAMA entity in NAND flash:
18 * 32 bit SEAMA magic 0x5EA3A417
20 * 16 bit metadata size (following the header)
22 * 16 bytes MD5 digest of the image
26 * Then if a new SEAMA magic follows, that is the next image.
29 #define SEAMA_MAGIC 0x5EA3A417
30 #define SEAMA_HDR_NO_META_SZ 28
31 #define SEAMA_MAX_META_SZ (1024 - SEAMA_HDR_NO_META_SZ)
38 u8 metadata[SEAMA_MAX_META_SZ];
41 static struct seama_header shdr;
43 static int env_set_val(const char *varname, ulong val)
47 ret = env_set_hex(varname, val);
49 printf("Failed to %s env var\n", varname);
54 static int do_seama_load_image(struct cmd_tbl *cmdtp, int flag, int argc,
59 unsigned long image_index;
68 if (argc < 2 || argc > 3)
71 load_addr = hextoul(argv[1], NULL);
73 printf("Invalid load address\n");
77 /* Can be 0 for first image */
78 image_index = hextoul(argv[2], NULL);
80 /* We only support one NAND, the first one */
82 mtd = get_nand_dev_by_index(0);
84 printf("NAND Device 0 not available\n");
85 return CMD_RET_FAILURE;
88 #ifdef CONFIG_SYS_NAND_SELECT_DEVICE
89 board_nand_select_device(mtd_to_nand(mtd), 0);
92 printf("Loading SEAMA image %lu from %s\n", image_index, mtd->name);
94 readsz = sizeof(shdr);
96 ret = nand_read_skip_bad(mtd, 0, &readsz, NULL, mtd->size,
99 printf("Read error reading SEAMA header\n");
100 return CMD_RET_FAILURE;
103 if (shdr.magic != SEAMA_MAGIC) {
104 printf("Invalid SEAMA image magic: 0x%08x\n", shdr.magic);
105 return CMD_RET_FAILURE;
108 /* Only the lower 16 bits are valid */
109 shdr.meta_size &= 0xFFFF;
111 if (env_set_val("seama_image_size", 0))
112 return CMD_RET_FAILURE;
114 printf("SEMA IMAGE:\n");
115 printf(" metadata size %d\n", shdr.meta_size);
116 printf(" image size %d\n", shdr.image_size);
117 printf(" checksum %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
118 shdr.md5[0], shdr.md5[1], shdr.md5[2], shdr.md5[3],
119 shdr.md5[4], shdr.md5[5], shdr.md5[6], shdr.md5[7],
120 shdr.md5[8], shdr.md5[9], shdr.md5[10], shdr.md5[11],
121 shdr.md5[12], shdr.md5[13], shdr.md5[14], shdr.md5[15]);
123 /* TODO: handle metadata if needed */
125 len = shdr.image_size;
126 if (env_set_val("seama_image_size", len))
127 return CMD_RET_FAILURE;
129 /* We need to include the header (read full pages) */
130 readsz = shdr.image_size + SEAMA_HDR_NO_META_SZ + shdr.meta_size;
131 ret = nand_read_skip_bad(mtd, 0, &readsz, NULL, mtd->size,
132 (u_char *)load_addr);
134 printf("Read error reading SEAMA main image\n");
135 return CMD_RET_FAILURE;
138 /* We use a temporary variable tmp to avoid to hairy casts */
139 start = (u32 *)load_addr;
141 tmp += SEAMA_HDR_NO_META_SZ + shdr.meta_size;
143 tmp += shdr.image_size;
146 printf("Decoding SEAMA image 0x%08x..0x%08x to 0x%08x\n",
147 (u32)offset, (u32)end, (u32)start);
148 for (; start < end; start++, offset++)
149 *start = be32_to_cpu(*offset);
151 return CMD_RET_SUCCESS;
155 (seama, 3, 1, do_seama_load_image,
156 "Load the SEAMA image and sets envs",
157 "seama <addr> <imageindex>\n"