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