blob: 04d86f87a86e5050d2e66de92dedd49af1f1ee02 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Marek Vasutc2cf4202011-11-08 23:18:18 +00002/*
3 * Freescale i.MX28 image generator
4 *
5 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
6 * on behalf of DENX Software Engineering GmbH
Marek Vasutc2cf4202011-11-08 23:18:18 +00007 */
8
9#include <fcntl.h>
10#include <sys/stat.h>
11#include <sys/types.h>
12#include <unistd.h>
13
14#include "compiler.h"
15
Jörg Krause2c9e16b2015-04-15 09:27:23 +020016/* Taken from <linux/kernel.h> */
17#define __round_mask(x, y) ((__typeof__(x))((y)-1))
18#define round_down(x, y) ((x) & ~__round_mask(x, y))
19
Marek Vasutc2cf4202011-11-08 23:18:18 +000020/*
21 * Default BCB layout.
22 *
23 * TWEAK this if you have blown any OCOTP fuses.
24 */
25#define STRIDE_PAGES 64
26#define STRIDE_COUNT 4
27
28/*
29 * Layout for 256Mb big NAND with 2048b page size, 64b OOB size and
30 * 128kb erase size.
31 *
32 * TWEAK this if you have different kind of NAND chip.
33 */
Marek Vasut462db722013-08-27 23:32:37 +020034static uint32_t nand_writesize = 2048;
35static uint32_t nand_oobsize = 64;
36static uint32_t nand_erasesize = 128 * 1024;
Marek Vasutc2cf4202011-11-08 23:18:18 +000037
38/*
39 * Sector on which the SigmaTel boot partition (0x53) starts.
40 */
Marek Vasut462db722013-08-27 23:32:37 +020041static uint32_t sd_sector = 2048;
Marek Vasutc2cf4202011-11-08 23:18:18 +000042
43/*
44 * Each of the U-Boot bootstreams is at maximum 1MB big.
45 *
46 * TWEAK this if, for some wild reason, you need to boot bigger image.
47 */
48#define MAX_BOOTSTREAM_SIZE (1 * 1024 * 1024)
49
50/* i.MX28 NAND controller-specific constants. DO NOT TWEAK! */
51#define MXS_NAND_DMA_DESCRIPTOR_COUNT 4
52#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE 512
53#define MXS_NAND_METADATA_SIZE 10
Jörg Krause1d870262015-04-15 09:27:22 +020054#define MXS_NAND_BITS_PER_ECC_LEVEL 13
Marek Vasutc2cf4202011-11-08 23:18:18 +000055#define MXS_NAND_COMMAND_BUFFER_SIZE 32
56
57struct mx28_nand_fcb {
58 uint32_t checksum;
59 uint32_t fingerprint;
60 uint32_t version;
61 struct {
62 uint8_t data_setup;
63 uint8_t data_hold;
64 uint8_t address_setup;
65 uint8_t dsample_time;
66 uint8_t nand_timing_state;
67 uint8_t rea;
68 uint8_t rloh;
69 uint8_t rhoh;
70 } timing;
71 uint32_t page_data_size;
72 uint32_t total_page_size;
73 uint32_t sectors_per_block;
74 uint32_t number_of_nands; /* Ignored */
75 uint32_t total_internal_die; /* Ignored */
76 uint32_t cell_type; /* Ignored */
77 uint32_t ecc_block_n_ecc_type;
78 uint32_t ecc_block_0_size;
79 uint32_t ecc_block_n_size;
80 uint32_t ecc_block_0_ecc_type;
81 uint32_t metadata_bytes;
82 uint32_t num_ecc_blocks_per_page;
83 uint32_t ecc_block_n_ecc_level_sdk; /* Ignored */
84 uint32_t ecc_block_0_size_sdk; /* Ignored */
85 uint32_t ecc_block_n_size_sdk; /* Ignored */
86 uint32_t ecc_block_0_ecc_level_sdk; /* Ignored */
87 uint32_t num_ecc_blocks_per_page_sdk; /* Ignored */
88 uint32_t metadata_bytes_sdk; /* Ignored */
89 uint32_t erase_threshold;
90 uint32_t boot_patch;
91 uint32_t patch_sectors;
92 uint32_t firmware1_starting_sector;
93 uint32_t firmware2_starting_sector;
94 uint32_t sectors_in_firmware1;
95 uint32_t sectors_in_firmware2;
96 uint32_t dbbt_search_area_start_address;
97 uint32_t badblock_marker_byte;
98 uint32_t badblock_marker_start_bit;
99 uint32_t bb_marker_physical_offset;
100};
101
102struct mx28_nand_dbbt {
103 uint32_t checksum;
104 uint32_t fingerprint;
105 uint32_t version;
106 uint32_t number_bb;
107 uint32_t number_2k_pages_bb;
108};
109
110struct mx28_nand_bbt {
111 uint32_t nand;
112 uint32_t number_bb;
113 uint32_t badblock[510];
114};
115
116struct mx28_sd_drive_info {
117 uint32_t chip_num;
118 uint32_t drive_type;
119 uint32_t tag;
120 uint32_t first_sector_number;
121 uint32_t sector_count;
122};
123
124struct mx28_sd_config_block {
125 uint32_t signature;
126 uint32_t primary_boot_tag;
127 uint32_t secondary_boot_tag;
128 uint32_t num_copies;
129 struct mx28_sd_drive_info drv_info[1];
130};
131
Jörg Krause2c9e16b2015-04-15 09:27:23 +0200132static inline uint32_t mx28_nand_ecc_chunk_cnt(uint32_t page_data_size)
133{
134 return page_data_size / MXS_NAND_CHUNK_DATA_CHUNK_SIZE;
135}
136
Marek Vasutc2cf4202011-11-08 23:18:18 +0000137static inline uint32_t mx28_nand_ecc_size_in_bits(uint32_t ecc_strength)
138{
Jörg Krause1d870262015-04-15 09:27:22 +0200139 return ecc_strength * MXS_NAND_BITS_PER_ECC_LEVEL;
Marek Vasutc2cf4202011-11-08 23:18:18 +0000140}
141
142static inline uint32_t mx28_nand_get_ecc_strength(uint32_t page_data_size,
143 uint32_t page_oob_size)
144{
Jörg Krause2c9e16b2015-04-15 09:27:23 +0200145 int ecc_strength;
Marek Vasutc2cf4202011-11-08 23:18:18 +0000146
Jörg Krause2c9e16b2015-04-15 09:27:23 +0200147 /*
148 * Determine the ECC layout with the formula:
149 * ECC bits per chunk = (total page spare data bits) /
150 * (bits per ECC level) / (chunks per page)
151 * where:
152 * total page spare data bits =
153 * (page oob size - meta data size) * (bits per byte)
154 */
155 ecc_strength = ((page_oob_size - MXS_NAND_METADATA_SIZE) * 8)
156 / (MXS_NAND_BITS_PER_ECC_LEVEL *
157 mx28_nand_ecc_chunk_cnt(page_data_size));
Marek Vasutc2cf4202011-11-08 23:18:18 +0000158
Jörg Krause2c9e16b2015-04-15 09:27:23 +0200159 return round_down(ecc_strength, 2);
Marek Vasutc2cf4202011-11-08 23:18:18 +0000160}
161
162static inline uint32_t mx28_nand_get_mark_offset(uint32_t page_data_size,
163 uint32_t ecc_strength)
164{
165 uint32_t chunk_data_size_in_bits;
166 uint32_t chunk_ecc_size_in_bits;
167 uint32_t chunk_total_size_in_bits;
168 uint32_t block_mark_chunk_number;
169 uint32_t block_mark_chunk_bit_offset;
170 uint32_t block_mark_bit_offset;
171
172 chunk_data_size_in_bits = MXS_NAND_CHUNK_DATA_CHUNK_SIZE * 8;
173 chunk_ecc_size_in_bits = mx28_nand_ecc_size_in_bits(ecc_strength);
174
175 chunk_total_size_in_bits =
176 chunk_data_size_in_bits + chunk_ecc_size_in_bits;
177
178 /* Compute the bit offset of the block mark within the physical page. */
179 block_mark_bit_offset = page_data_size * 8;
180
181 /* Subtract the metadata bits. */
182 block_mark_bit_offset -= MXS_NAND_METADATA_SIZE * 8;
183
184 /*
185 * Compute the chunk number (starting at zero) in which the block mark
186 * appears.
187 */
188 block_mark_chunk_number =
189 block_mark_bit_offset / chunk_total_size_in_bits;
190
191 /*
192 * Compute the bit offset of the block mark within its chunk, and
193 * validate it.
194 */
195 block_mark_chunk_bit_offset = block_mark_bit_offset -
196 (block_mark_chunk_number * chunk_total_size_in_bits);
197
198 if (block_mark_chunk_bit_offset > chunk_data_size_in_bits)
199 return 1;
200
201 /*
202 * Now that we know the chunk number in which the block mark appears,
203 * we can subtract all the ECC bits that appear before it.
204 */
205 block_mark_bit_offset -=
206 block_mark_chunk_number * chunk_ecc_size_in_bits;
207
208 return block_mark_bit_offset;
209}
210
211static inline uint32_t mx28_nand_mark_byte_offset(void)
212{
213 uint32_t ecc_strength;
214 ecc_strength = mx28_nand_get_ecc_strength(nand_writesize, nand_oobsize);
215 return mx28_nand_get_mark_offset(nand_writesize, ecc_strength) >> 3;
216}
217
218static inline uint32_t mx28_nand_mark_bit_offset(void)
219{
220 uint32_t ecc_strength;
221 ecc_strength = mx28_nand_get_ecc_strength(nand_writesize, nand_oobsize);
222 return mx28_nand_get_mark_offset(nand_writesize, ecc_strength) & 0x7;
223}
224
225static uint32_t mx28_nand_block_csum(uint8_t *block, uint32_t size)
226{
227 uint32_t csum = 0;
228 int i;
229
230 for (i = 0; i < size; i++)
231 csum += block[i];
232
233 return csum ^ 0xffffffff;
234}
235
236static struct mx28_nand_fcb *mx28_nand_get_fcb(uint32_t size)
237{
238 struct mx28_nand_fcb *fcb;
239 uint32_t bcb_size_bytes;
240 uint32_t stride_size_bytes;
241 uint32_t bootstream_size_pages;
242 uint32_t fw1_start_page;
243 uint32_t fw2_start_page;
244
245 fcb = malloc(nand_writesize);
246 if (!fcb) {
247 printf("MX28 NAND: Unable to allocate FCB\n");
248 return NULL;
249 }
250
251 memset(fcb, 0, nand_writesize);
252
253 fcb->fingerprint = 0x20424346;
254 fcb->version = 0x01000000;
255
256 /*
257 * FIXME: These here are default values as found in kobs-ng. We should
258 * probably retrieve the data from NAND or something.
259 */
260 fcb->timing.data_setup = 80;
261 fcb->timing.data_hold = 60;
262 fcb->timing.address_setup = 25;
263 fcb->timing.dsample_time = 6;
264
265 fcb->page_data_size = nand_writesize;
266 fcb->total_page_size = nand_writesize + nand_oobsize;
267 fcb->sectors_per_block = nand_erasesize / nand_writesize;
268
269 fcb->num_ecc_blocks_per_page = (nand_writesize / 512) - 1;
270 fcb->ecc_block_0_size = 512;
271 fcb->ecc_block_n_size = 512;
272 fcb->metadata_bytes = 10;
Jörg Krauseb8898e42015-08-11 13:44:26 +0200273 fcb->ecc_block_n_ecc_type = mx28_nand_get_ecc_strength(
274 nand_writesize, nand_oobsize) >> 1;
275 fcb->ecc_block_0_ecc_type = mx28_nand_get_ecc_strength(
276 nand_writesize, nand_oobsize) >> 1;
Marek Vasutc2cf4202011-11-08 23:18:18 +0000277 if (fcb->ecc_block_n_ecc_type == 0) {
278 printf("MX28 NAND: Unsupported NAND geometry\n");
279 goto err;
280 }
281
282 fcb->boot_patch = 0;
283 fcb->patch_sectors = 0;
284
285 fcb->badblock_marker_byte = mx28_nand_mark_byte_offset();
286 fcb->badblock_marker_start_bit = mx28_nand_mark_bit_offset();
287 fcb->bb_marker_physical_offset = nand_writesize;
288
289 stride_size_bytes = STRIDE_PAGES * nand_writesize;
290 bcb_size_bytes = stride_size_bytes * STRIDE_COUNT;
291
292 bootstream_size_pages = (size + (nand_writesize - 1)) /
293 nand_writesize;
294
295 fw1_start_page = 2 * bcb_size_bytes / nand_writesize;
296 fw2_start_page = (2 * bcb_size_bytes + MAX_BOOTSTREAM_SIZE) /
297 nand_writesize;
298
299 fcb->firmware1_starting_sector = fw1_start_page;
300 fcb->firmware2_starting_sector = fw2_start_page;
301 fcb->sectors_in_firmware1 = bootstream_size_pages;
302 fcb->sectors_in_firmware2 = bootstream_size_pages;
303
304 fcb->dbbt_search_area_start_address = STRIDE_PAGES * STRIDE_COUNT;
305
306 return fcb;
307
308err:
309 free(fcb);
310 return NULL;
311}
312
313static struct mx28_nand_dbbt *mx28_nand_get_dbbt(void)
314{
315 struct mx28_nand_dbbt *dbbt;
316
317 dbbt = malloc(nand_writesize);
318 if (!dbbt) {
319 printf("MX28 NAND: Unable to allocate DBBT\n");
320 return NULL;
321 }
322
323 memset(dbbt, 0, nand_writesize);
324
325 dbbt->fingerprint = 0x54424244;
326 dbbt->version = 0x1;
327
328 return dbbt;
329}
330
331static inline uint8_t mx28_nand_parity_13_8(const uint8_t b)
332{
333 uint32_t parity = 0, tmp;
334
335 tmp = ((b >> 6) ^ (b >> 5) ^ (b >> 3) ^ (b >> 2)) & 1;
336 parity |= tmp << 0;
337
338 tmp = ((b >> 7) ^ (b >> 5) ^ (b >> 4) ^ (b >> 2) ^ (b >> 1)) & 1;
339 parity |= tmp << 1;
340
341 tmp = ((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ (b >> 1) ^ (b >> 0)) & 1;
342 parity |= tmp << 2;
343
344 tmp = ((b >> 7) ^ (b >> 4) ^ (b >> 3) ^ (b >> 0)) & 1;
345 parity |= tmp << 3;
346
347 tmp = ((b >> 6) ^ (b >> 4) ^ (b >> 3) ^
348 (b >> 2) ^ (b >> 1) ^ (b >> 0)) & 1;
349 parity |= tmp << 4;
350
351 return parity;
352}
353
354static uint8_t *mx28_nand_fcb_block(struct mx28_nand_fcb *fcb)
355{
356 uint8_t *block;
357 uint8_t *ecc;
358 int i;
359
360 block = malloc(nand_writesize + nand_oobsize);
361 if (!block) {
362 printf("MX28 NAND: Unable to allocate FCB block\n");
363 return NULL;
364 }
365
366 memset(block, 0, nand_writesize + nand_oobsize);
367
368 /* Update the FCB checksum */
369 fcb->checksum = mx28_nand_block_csum(((uint8_t *)fcb) + 4, 508);
370
371 /* Figure 12-11. in iMX28RM, rev. 1, says FCB is at offset 12 */
372 memcpy(block + 12, fcb, sizeof(struct mx28_nand_fcb));
373
374 /* ECC is at offset 12 + 512 */
375 ecc = block + 12 + 512;
376
377 /* Compute the ECC parity */
378 for (i = 0; i < sizeof(struct mx28_nand_fcb); i++)
379 ecc[i] = mx28_nand_parity_13_8(block[i + 12]);
380
381 return block;
382}
383
Marek Vasut41f0d222013-08-27 23:32:38 +0200384static int mx28_nand_write_fcb(struct mx28_nand_fcb *fcb, uint8_t *buf)
Marek Vasutc2cf4202011-11-08 23:18:18 +0000385{
386 uint32_t offset;
387 uint8_t *fcbblock;
388 int ret = 0;
389 int i;
390
391 fcbblock = mx28_nand_fcb_block(fcb);
392 if (!fcbblock)
393 return -1;
394
395 for (i = 0; i < STRIDE_PAGES * STRIDE_COUNT; i += STRIDE_PAGES) {
396 offset = i * nand_writesize;
397 memcpy(buf + offset, fcbblock, nand_writesize + nand_oobsize);
Marek Vasut41f0d222013-08-27 23:32:38 +0200398 /* Mark the NAND page is OK. */
399 buf[offset + nand_writesize] = 0xff;
Marek Vasutc2cf4202011-11-08 23:18:18 +0000400 }
401
402 free(fcbblock);
403 return ret;
404}
405
Marek Vasut41f0d222013-08-27 23:32:38 +0200406static int mx28_nand_write_dbbt(struct mx28_nand_dbbt *dbbt, uint8_t *buf)
Marek Vasutc2cf4202011-11-08 23:18:18 +0000407{
408 uint32_t offset;
409 int i = STRIDE_PAGES * STRIDE_COUNT;
410
411 for (; i < 2 * STRIDE_PAGES * STRIDE_COUNT; i += STRIDE_PAGES) {
412 offset = i * nand_writesize;
413 memcpy(buf + offset, dbbt, sizeof(struct mx28_nand_dbbt));
414 }
415
416 return 0;
417}
418
419static int mx28_nand_write_firmware(struct mx28_nand_fcb *fcb, int infd,
Marek Vasut41f0d222013-08-27 23:32:38 +0200420 uint8_t *buf)
Marek Vasutc2cf4202011-11-08 23:18:18 +0000421{
422 int ret;
423 off_t size;
424 uint32_t offset1, offset2;
425
426 size = lseek(infd, 0, SEEK_END);
427 lseek(infd, 0, SEEK_SET);
428
429 offset1 = fcb->firmware1_starting_sector * nand_writesize;
430 offset2 = fcb->firmware2_starting_sector * nand_writesize;
431
432 ret = read(infd, buf + offset1, size);
433 if (ret != size)
434 return -1;
435
436 memcpy(buf + offset2, buf + offset1, size);
437
438 return 0;
439}
440
Marek Vasut462db722013-08-27 23:32:37 +0200441static void usage(void)
Marek Vasutc2cf4202011-11-08 23:18:18 +0000442{
443 printf(
Otavio Salvadored2b7a12012-03-17 09:16:50 +0000444 "Usage: mxsboot [ops] <type> <infile> <outfile>\n"
Marek Vasutc2cf4202011-11-08 23:18:18 +0000445 "Augment BootStream file with a proper header for i.MX28 boot\n"
446 "\n"
447 " <type> type of image:\n"
448 " \"nand\" for NAND image\n"
449 " \"sd\" for SD image\n"
450 " <infile> input file, the u-boot.sb bootstream\n"
451 " <outfile> output file, the bootable image\n"
452 "\n");
453 printf(
454 "For NAND boot, these options are accepted:\n"
455 " -w <size> NAND page size\n"
456 " -o <size> NAND OOB size\n"
457 " -e <size> NAND erase size\n"
458 "\n"
459 "For SD boot, these options are accepted:\n"
460 " -p <sector> Sector where the SGTL partition starts\n"
461 );
462}
463
464static int mx28_create_nand_image(int infd, int outfd)
465{
466 struct mx28_nand_fcb *fcb;
467 struct mx28_nand_dbbt *dbbt;
468 int ret = -1;
Marek Vasut41f0d222013-08-27 23:32:38 +0200469 uint8_t *buf;
Marek Vasutc2cf4202011-11-08 23:18:18 +0000470 int size;
471 ssize_t wr_size;
472
473 size = nand_writesize * 512 + 2 * MAX_BOOTSTREAM_SIZE;
474
475 buf = malloc(size);
476 if (!buf) {
477 printf("Can not allocate output buffer of %d bytes\n", size);
478 goto err0;
479 }
480
481 memset(buf, 0, size);
482
483 fcb = mx28_nand_get_fcb(MAX_BOOTSTREAM_SIZE);
484 if (!fcb) {
485 printf("Unable to compile FCB\n");
486 goto err1;
487 }
488
489 dbbt = mx28_nand_get_dbbt();
490 if (!dbbt) {
491 printf("Unable to compile DBBT\n");
492 goto err2;
493 }
494
495 ret = mx28_nand_write_fcb(fcb, buf);
496 if (ret) {
497 printf("Unable to write FCB to buffer\n");
498 goto err3;
499 }
500
501 ret = mx28_nand_write_dbbt(dbbt, buf);
502 if (ret) {
503 printf("Unable to write DBBT to buffer\n");
504 goto err3;
505 }
506
507 ret = mx28_nand_write_firmware(fcb, infd, buf);
508 if (ret) {
509 printf("Unable to write firmware to buffer\n");
510 goto err3;
511 }
512
513 wr_size = write(outfd, buf, size);
514 if (wr_size != size) {
515 ret = -1;
516 goto err3;
517 }
518
519 ret = 0;
520
521err3:
522 free(dbbt);
523err2:
524 free(fcb);
525err1:
526 free(buf);
527err0:
528 return ret;
529}
530
531static int mx28_create_sd_image(int infd, int outfd)
532{
533 int ret = -1;
534 uint32_t *buf;
535 int size;
536 off_t fsize;
537 ssize_t wr_size;
538 struct mx28_sd_config_block *cb;
539
540 fsize = lseek(infd, 0, SEEK_END);
541 lseek(infd, 0, SEEK_SET);
Otavio Salvador3a0be4a2013-04-24 11:23:27 +0000542 size = fsize + 4 * 512;
Marek Vasutc2cf4202011-11-08 23:18:18 +0000543
544 buf = malloc(size);
545 if (!buf) {
546 printf("Can not allocate output buffer of %d bytes\n", size);
547 goto err0;
548 }
549
Otavio Salvador3a0be4a2013-04-24 11:23:27 +0000550 ret = read(infd, (uint8_t *)buf + 4 * 512, fsize);
Marek Vasutc2cf4202011-11-08 23:18:18 +0000551 if (ret != fsize) {
552 ret = -1;
553 goto err1;
554 }
555
556 cb = (struct mx28_sd_config_block *)buf;
557
Bin Mengef881232016-01-24 19:38:32 -0800558 cb->signature = cpu_to_le32(0x00112233);
559 cb->primary_boot_tag = cpu_to_le32(0x1);
560 cb->secondary_boot_tag = cpu_to_le32(0x1);
561 cb->num_copies = cpu_to_le32(1);
562 cb->drv_info[0].chip_num = cpu_to_le32(0x0);
563 cb->drv_info[0].drive_type = cpu_to_le32(0x0);
564 cb->drv_info[0].tag = cpu_to_le32(0x1);
565 cb->drv_info[0].first_sector_number = cpu_to_le32(sd_sector + 4);
566 cb->drv_info[0].sector_count = cpu_to_le32((size - 4) / 512);
Marek Vasutc2cf4202011-11-08 23:18:18 +0000567
568 wr_size = write(outfd, buf, size);
569 if (wr_size != size) {
570 ret = -1;
571 goto err1;
572 }
573
574 ret = 0;
575
576err1:
577 free(buf);
578err0:
579 return ret;
580}
581
Marek Vasut462db722013-08-27 23:32:37 +0200582static int parse_ops(int argc, char **argv)
Marek Vasutc2cf4202011-11-08 23:18:18 +0000583{
584 int i;
585 int tmp;
586 char *end;
587 enum param {
588 PARAM_WRITE,
589 PARAM_OOB,
590 PARAM_ERASE,
591 PARAM_PART,
592 PARAM_SD,
593 PARAM_NAND
594 };
595 int type;
596
Marek Vasut0d429a62011-12-22 09:55:08 +0000597 if (argc < 4)
598 return -1;
599
Marek Vasutc2cf4202011-11-08 23:18:18 +0000600 for (i = 1; i < argc; i++) {
601 if (!strncmp(argv[i], "-w", 2))
602 type = PARAM_WRITE;
603 else if (!strncmp(argv[i], "-o", 2))
604 type = PARAM_OOB;
605 else if (!strncmp(argv[i], "-e", 2))
606 type = PARAM_ERASE;
607 else if (!strncmp(argv[i], "-p", 2))
608 type = PARAM_PART;
609 else /* SD/MMC */
610 break;
611
612 tmp = strtol(argv[++i], &end, 10);
613 if (tmp % 2)
614 return -1;
615 if (tmp <= 0)
616 return -1;
617
618 if (type == PARAM_WRITE)
619 nand_writesize = tmp;
620 if (type == PARAM_OOB)
621 nand_oobsize = tmp;
622 if (type == PARAM_ERASE)
623 nand_erasesize = tmp;
624 if (type == PARAM_PART)
625 sd_sector = tmp;
626 }
627
628 if (strcmp(argv[i], "sd") && strcmp(argv[i], "nand"))
629 return -1;
630
631 if (i + 3 != argc)
632 return -1;
633
634 return i;
635}
636
637int main(int argc, char **argv)
638{
639 int infd, outfd;
640 int ret = 0;
641 int offset;
642
643 offset = parse_ops(argc, argv);
644 if (offset < 0) {
645 usage();
646 ret = 1;
647 goto err1;
648 }
649
650 infd = open(argv[offset + 1], O_RDONLY);
651 if (infd < 0) {
652 printf("Input BootStream file can not be opened\n");
653 ret = 2;
654 goto err1;
655 }
656
657 outfd = open(argv[offset + 2], O_CREAT | O_TRUNC | O_WRONLY,
658 S_IRUSR | S_IWUSR);
659 if (outfd < 0) {
660 printf("Output file can not be created\n");
661 ret = 3;
662 goto err2;
663 }
664
665 if (!strcmp(argv[offset], "sd"))
666 ret = mx28_create_sd_image(infd, outfd);
667 else if (!strcmp(argv[offset], "nand"))
668 ret = mx28_create_nand_image(infd, outfd);
669
670 close(outfd);
671err2:
672 close(infd);
673err1:
674 return ret;
675}