This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

C642x ROM bootloader reference code review

Hi!

I would like to request a reference code for C6424 internal ROM bootloader since there are no some valuable details in bootloader docs, namely SPRAAK5.

I have implemented a U-Boot command (for my board) that writes AIS image to NAND using bootloader ECC layout. It works fine for now. But once I tried to emulate bad blocks it fails to boot. I used signature 0xBADDBADD that was put in OOB at offset 4. I tried both little endian and big endian representation of signature. However I did not destroy ECC values in OOB, so the read status itself does not report an ECC error. However, the document SPRAAK5 states that bootloader just tests the signature in OOB to skip it. Nothing is said whether it occurs as error handling condition due to wrong ECC or just each time a page is read from NAND.

I would like to have a look on bootloader source code to support bad blocks marking in my U-boot implementation.

  • Vladimir,

    I do not believe there is source code that can be made publicly available. The information in the Bootloader User Guide is what is available, in this case.

    Which revision of silicon do you have?

    Which device number are you using, with the number instead of the 'x'?

    Are you using a secondary bootloader or only the ROM bootloader?

    In which block or blocks did you place the 0xBADDBADD code in OOB offset 4?

    Regards,
    RandyP

  • Randy, 

    I am now holding in my hands a book named TMS320C3x User's Guide, revision J, October 1994. This book contains Appendix G which is named "Boot Loader Source Code". 15 years ago this source helped me to catch some bugs, mainly due to knowledge of stack location and use of some CPU registers. It is a great problem that TI has embarked on a path of hiding or poorly documenting technical details of modern processors. Unfortunately, this is not the only case of such TI behaviour. While the average level of documentation is still high there is a trend for worsening its quality, or technical support.

    Ok, let's get back to the boot loader.

    1) We are dealing with chips of the following top-side marking: TMS320C6424ZWT, $NC-09A04QW, L2, E1

    As I understand, this is a revision 1.3 of silicon.

    2) We have MM_REVID (@0x01812000) value of 0x00020002.

    3) We have JTAGID (@0x01c40028) value of 0x0B72102F.

    We are using original DSP built-in ROM boot loader to boot AIS image with U-boot from external NAND FLASH. We use TI-style ECC layout in OOB only for the U-Boot partition. All other partitions of NAND are operated under either U-Boot or linux which both have the same OOB layout but different from the layout of TI ROM boot loader.

    I have implemented U-Boot AIS update command which writes AIS image to NAND using ECC layout of ROM boot loader. It works now for the case of no bad blocks in U-Boot partition. However, when I tried to add signature of bad page, to emulate bad page, I got a hangup on boot. This is not a big problem because U-boot is small enough (just 2 blocks of NAND) but I would like to have more reliable AIS update script.

    Here is a bit of my U-Boot code used to write AIS image into NAND:

    ---
    printf("Writing AIS image starting at 0x%08x...\n", offs);
    total_pages = 0, bad_pages = 0;
    do {
    mtd_oob_ops_t opts = {
    .datbuf = out,
    .oobbuf = out + page_size,
    .len = page_size,
    .ooblen = oob_size,
    .mode = MTD_OOB_RAW
    };
      // prepare buffer with ECC
    memcpy(out, buf, page_size);
      // padd data with 0xFF
    if (size < page_size)
    memset(out+size, 0xff, page_size-size);
      // calculate ECC and fill in the OOB
    ecc_page( out, out );
      // writing page to nand
    ret = nand->write_oob(nand, offs, &opts );
      // if (total_pages==4) ret = -74;
      if (ret!=0) { // error occured precess it
    printf("Error writing NAND page at 0x%08x (rc=%d)...\n", offs, ret );
        // note: bootloader looks for AIS image start
    // at block boundary
    if (offs == offset)
    offs += nand->erasesize;
    else {
    // mark page as bad and retry
    *((unsigned*)(out+page_size+4)) = 0xBADDBADD;
    nand->write_oob(nand, offs, &opts );
    offs += page_size;
    }
    bad_pages++;
    }
    else
    {
    // normally go next page
    buf += page_size;
    offs += page_size;
        size -= (size>=page_size) ? page_size : size;
    }
    total_pages++;
    } while( size!=0 );
    printf("Done! Total of %u pages written, %u marked bad.\n", total_pages, bad_pages );
    ---
    I used the line "if (total_pages==4) ret = -74;" to emulate bad page. However, as you see I just add 0xbaddbadd word into OOB at offset 4 and do not wrack ECC. I suspect that ROM boot loader actually checks for 0xbaddbadd only in case when ECC check fails, to discover what to do, to stop booting or just to skip one bad page. That's why I want ot have a look on it source.
  • Vladimir,

    Please try the following two tests to help determine the validity of your test and to validate the way the RBL operates:

    1. Write the 0xBADDBADD code to one or more blocks starting with block 1. See if this will allow the boot to progress normally, simply delaying the start of the AIS code to a later block. Then all of the remaining AIS code should be in contiguous blocks.

    2. With 0xBADDBADD written the way you show above (page 4), compare the signal signatures on the EMIF with the way they appear when you have no 0xBADDBADD code written. The issue to be confirmed here is whether the NAND boot aborts and restarts (signature appears to be looping on 4 pages  [edited]) or continues and finds further errors.

    Regards,
    RandyP

  • Randy,

    can you clarify your term of block? It seems i don't understand TI terminology. My NAND has 64 pages per erase block. Page is 2048 bytes while an erase block is 128K. I thought that 'block' means an 'erase block'. However, descriprion of RBL operetes with blocks but OOB is a per-page data. So, this is not obviuos where shoud I put 0xBADDBADD signature?

    My thought was that I can skip a single bad page, not to waste a whole erase block. Consider I am writing page 10 of block 1 (erase block #1). If I see a error there, should I mark only this page, or roll back to page 0 and write signature to page 0 of block 1, then, discarding all 128 pages?

  • Vladimir,

    In my #2 above, I should have said "page 4" which is where you were writing 0xBADDBADD. My error caused this confusion.

    In searching for the start of the AIS data, the RBL will skip the first Block of Pages (Block 0). The RBL will start with Block=1 Page=0 and try to find the Magic Number. If not found there, it will move to Block=2 Page=0 and look there for the Magic Number, continuing to skip entire Blocks until it finds a Magic Number in Block=N Page=0.

    Starting from Block=N Page=0, the RBL will then read data to the end of Block=N Page=0, then move to Block=N Page=1, and so on to the end of the last Page of Block=N. It will then move to Block=N+1 Page=0.

    If there is ever an error condition when reading any Page, that Page and all remaining Pages of that Block will be skipped and the RBL will resume reading from the next Block at Page=0. An error condition includes reading the 0xBADDBADD in the OOB area of a Page, any Page in sequence.

    So for your testing, if you begin your AIS data being stored in Block=1 Page=0 and put data into Pages 0 through 3, then you may write 0xBADDBADD into the second word of the OOB area of Block=1 Page=4. You would then resume writing AIS data into Block=2 Page=0 as the continuation after what was in Block=1 Page=3.

    Please let me know how this works for you, and anything you learn from it.

    Regards,
    RandyP

  • Randy,

    Thanks, I will try your version. However, it is strange, why should we waste all pages of a block if we have just one bad page?

    You reply made me to review BSL code for 6424 (oh, TI should write better code, not SO muddy as the following example). Here it is:

    // Generic function to write a UBL or Application header and the associated data
    Uint32 NAND_WriteHeaderAndData(PNAND_INFO pNandInfo, NAND_BOOT *nandBoot, Uint8 *srcBuf, Uint8 *gNandRx)
    {
    Uint32 endBlockNum;
    Uint32 blockNum;
    Uint32 pageNum;
    Uint32 count;
    Uint32 countMask;
    Uint32 numBlks;
    Uint8* inputData;

    // Get total number of blocks needed
    numBlks = 0;
    while ( (numBlks * pNandInfo->pagesPerBlock) < (nandBoot->numPage + 1) )
    {
    numBlks++;
    }
    //printf("Number of blocks needed for writing: %d\n",numBlks);
     // Check whether writing UBL or APP (based on destination block)
    blockNum = nandBoot->block;
    if (blockNum == START_BLOCK_NUM)
    {
    endBlockNum = END_BLOCK_NUM;
    }
    else
    {
    return E_FAIL; /* Block number is out of range */
    }
    NAND_WRITE_RETRY:
     if (blockNum > endBlockNum)
    {
    return E_FAIL;
    }
    //printf("Attempting to start in block number %d\n", blockNum);
     // Unprotect all needed blocks of the Flash 
    //if (NAND_UnProtectBlocks(blockNum,numBlks) != E_PASS)
    //{
    // blockNum++;
    // UARTSendData((Uint8 *)"Unprotect failed\n", FALSE);
    // goto NAND_WRITE_RETRY;
    //}
     // Erase the block where the header goes and the data starts
    if (NAND_EraseBlocks(pNandInfo, blockNum, numBlks) != E_PASS)
    {
    blockNum++;
    printf("Erase failed.\n");
    goto NAND_WRITE_RETRY;
    }
     // Setup header to be written
    _mem4( srcBuf + 4 ) = numBlks;
    _mem4( srcBuf + 8 ) = blockNum;
    _mem4( srcBuf + 12 ) = 0;

    inputData = srcBuf;

    // The following assumes power of 2 page_cnt - *should* always be valid
    countMask = (Uint32)pNandInfo->pagesPerBlock - 1;
     // Write AIS data pages
    count = 0;
    //printf("Writing %d bytes of data:\n", pNandInfo->bytesPerPage);
    do {
    // Write data to page
    pageNum = count & countMask;
    if( NAND_WritePage(pNandInfo, blockNum, pageNum, inputData) != E_PASS )
    {
    printf("NAND_WritePage() failed.\n");
    printf("Skipping bad block at block number :%d:\n", blockNum);
    #ifdef USE_ECC
    // Mark this block as bad block
    spareRegion[1] = BAD_BLOCK_FLAG;
    NAND_WriteSpareBytes( pNandInfo, blockNum, 0, (Uint8*) &spareRegion);
    spareRegion[1] = 0xFFFFFFFFu;
    #endif
    blockNum++;
    goto NAND_WRITE_RETRY;
    }
     waitloop(1000);

    // Verify the page just written
    pageNum = count & countMask;
    if (NAND_VerifyPage( pNandInfo, blockNum, pageNum, inputData, gNandRx) != E_PASS)
    {
    printf("NAND_VerifyPage() failed.\n");
    printf("Skipping bad block at block number :%d:\n", blockNum);
    // Mark this block as bad block
    #ifdef USE_ECC
    spareRegion[1] = BAD_BLOCK_FLAG;
    NAND_WriteSpareBytes( pNandInfo, blockNum, 0, (Uint8*) &spareRegion);
    spareRegion[1] = 0xFFFFFFFFu;
    #endif
    blockNum++;
    goto NAND_WRITE_RETRY;
    }

    count++;
    inputData += pNandInfo->bytesPerPage;
    if (!(count & countMask))
    {
    blockNum++;
    }
    } while (count < nandBoot->numPage);
     return E_PASS;
    }

    ---

    Is this code valid? Does it match with bootloader in ROM? As I see from this code, it will:

    1) write 0xBADDBADD signature to page 0 of a block, thus, destroying the status of ALL pages written correctly before a bad page.

    2) inputData is set to srcBuf on each error, thus, it will give incorrect image if error occurs in the middle of an image.

    3) waste whole block in case of one error page but it has very tight limit on available blocks, only 4 blocks for BSL code (END_BLOCK_NUM=5).

    4) in case of retry it will still erase blocks beyond END_BLOCK_NUM limit, thus, destroying any user content in NAND.

    to say nothing of a style of coding all this...

  • Vladimir,

    You are welcome for the detail on the RBL, greater detail than what is included in the Bootloader Application Note but not required for using the ROM Bootloader. Please do let us know if your practical testing matches my interpretive detail.

    Have you tried the NAND_WriteHeaderAndData function? I am curious if you have any problems with its use in application. That will be the better test than I can offer by mental simulation of the code.

    Your description, the method of eliminating entire blocks when any bad page is found, is how I interpret the Bootloader Application Note. My description represents a functional subset of that, skipping all of the remainder of a block. In one case it skips all of a block from Page=0, and in the other case from Page=N.

    Regards,
    RandyP