blob: 3c8e819923400c93d3957e99d23ab9e1862fcb84 [file] [log] [blame]
Linus Walleij41a29f22023-02-01 00:16:13 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2023 Linus Walleij <linus.walleij@linaro.org>
4 * Support for the "SEAttle iMAge" SEAMA NAND image format
5 */
6
Linus Walleij41a29f22023-02-01 00:16:13 +01007#include <command.h>
8#include <nand.h>
9
10/*
11 * All SEAMA data is stored in the flash in "network endianness"
12 * i.e. big endian, which means that it needs to be byte-swapped
13 * on all little endian platforms.
14 *
15 * structure for a SEAMA entity in NAND flash:
16 *
17 * 32 bit SEAMA magic 0x5EA3A417
18 * 16 bit reserved
19 * 16 bit metadata size (following the header)
20 * 32 bit image size
21 * 16 bytes MD5 digest of the image
22 * meta data
23 * ... image data ...
24 *
25 * Then if a new SEAMA magic follows, that is the next image.
26 */
27
28#define SEAMA_MAGIC 0x5EA3A417
29#define SEAMA_HDR_NO_META_SZ 28
30#define SEAMA_MAX_META_SZ (1024 - SEAMA_HDR_NO_META_SZ)
31
32struct seama_header {
33 u32 magic;
34 u32 meta_size;
35 u32 image_size;
36 u8 md5[16];
37 u8 metadata[SEAMA_MAX_META_SZ];
38};
39
40static struct seama_header shdr;
41
42static int env_set_val(const char *varname, ulong val)
43{
44 int ret;
45
46 ret = env_set_hex(varname, val);
47 if (ret)
48 printf("Failed to %s env var\n", varname);
49
50 return ret;
51}
52
53static int do_seama_load_image(struct cmd_tbl *cmdtp, int flag, int argc,
54 char *const argv[])
55{
56 struct mtd_info *mtd;
57 uintptr_t load_addr;
58 unsigned long image_index;
59 u32 len;
60 size_t readsz;
61 int ret;
62 u32 *start;
63 u32 *offset;
64 u32 *end;
65 u32 tmp;
66
67 if (argc < 2 || argc > 3)
68 return CMD_RET_USAGE;
69
70 load_addr = hextoul(argv[1], NULL);
71 if (!load_addr) {
72 printf("Invalid load address\n");
73 return CMD_RET_USAGE;
74 }
75
76 /* Can be 0 for first image */
77 image_index = hextoul(argv[2], NULL);
78
79 /* We only support one NAND, the first one */
80 nand_curr_device = 0;
81 mtd = get_nand_dev_by_index(0);
82 if (!mtd) {
83 printf("NAND Device 0 not available\n");
84 return CMD_RET_FAILURE;
85 }
86
87#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
88 board_nand_select_device(mtd_to_nand(mtd), 0);
89#endif
90
91 printf("Loading SEAMA image %lu from %s\n", image_index, mtd->name);
92
93 readsz = sizeof(shdr);
94 offset = 0;
95 ret = nand_read_skip_bad(mtd, 0, &readsz, NULL, mtd->size,
96 (u_char *)&shdr);
97 if (ret) {
98 printf("Read error reading SEAMA header\n");
99 return CMD_RET_FAILURE;
100 }
101
102 if (shdr.magic != SEAMA_MAGIC) {
103 printf("Invalid SEAMA image magic: 0x%08x\n", shdr.magic);
104 return CMD_RET_FAILURE;
105 }
106
107 /* Only the lower 16 bits are valid */
108 shdr.meta_size &= 0xFFFF;
109
110 if (env_set_val("seama_image_size", 0))
111 return CMD_RET_FAILURE;
112
113 printf("SEMA IMAGE:\n");
114 printf(" metadata size %d\n", shdr.meta_size);
115 printf(" image size %d\n", shdr.image_size);
116 printf(" checksum %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
117 shdr.md5[0], shdr.md5[1], shdr.md5[2], shdr.md5[3],
118 shdr.md5[4], shdr.md5[5], shdr.md5[6], shdr.md5[7],
119 shdr.md5[8], shdr.md5[9], shdr.md5[10], shdr.md5[11],
120 shdr.md5[12], shdr.md5[13], shdr.md5[14], shdr.md5[15]);
121
122 /* TODO: handle metadata if needed */
123
124 len = shdr.image_size;
125 if (env_set_val("seama_image_size", len))
126 return CMD_RET_FAILURE;
127
128 /* We need to include the header (read full pages) */
129 readsz = shdr.image_size + SEAMA_HDR_NO_META_SZ + shdr.meta_size;
130 ret = nand_read_skip_bad(mtd, 0, &readsz, NULL, mtd->size,
131 (u_char *)load_addr);
132 if (ret) {
133 printf("Read error reading SEAMA main image\n");
134 return CMD_RET_FAILURE;
135 }
136
137 /* We use a temporary variable tmp to avoid to hairy casts */
138 start = (u32 *)load_addr;
139 tmp = (u32)start;
140 tmp += SEAMA_HDR_NO_META_SZ + shdr.meta_size;
141 offset = (u32 *)tmp;
142 tmp += shdr.image_size;
143 end = (u32 *)tmp;
144
145 printf("Decoding SEAMA image 0x%08x..0x%08x to 0x%08x\n",
146 (u32)offset, (u32)end, (u32)start);
147 for (; start < end; start++, offset++)
148 *start = be32_to_cpu(*offset);
149
150 return CMD_RET_SUCCESS;
151}
152
153U_BOOT_CMD
154 (seama, 3, 1, do_seama_load_image,
155 "Load the SEAMA image and sets envs",
156 "seama <addr> <imageindex>\n"
157);