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.

K2H's DDR is not stable in 1600MHz.


HI , I encountered a problem of DDR error in my K2H board with DDR3A 1600MHz setting.
the message is below.


---------------start
U-Boot 2013.01 (Jun 16 2014 - 15:25:28)

I2C:   ready
Cannot read DIMM params
Detected SO-DIMM []

Reseting entire DDR3 memory to 0 ...
DRAM:  2 GiB
NAND:     512 MiB...

*** Warning - bad CRC, using default environment
---------------end


uboot read environment parameter from NAND Flash and it calculate CRC and check that the CRC value is correct or not.
after I set DDR3A to 1600MHz, sometimes the CRC value is correct, sometimes the CRC value is incorrect.
but when I set DDR3A to 1333MHz in my K2H board, the CRC value is always normally.

CRC error never appear when DDR3A set to 1333MHz.

I have done one experiment in DDR3A1600MHz. I modify CRC calculating code(copy from Nand Flash and calculate CRC) to uboot command.
if K2H board boot up and the CRC calculating is correct, I usually get the same correct result when I run the same CRC calculating code in uboot.
if K2H board boot up and the CRC calculating is incorrect, I get most incorrect result when I run the same CRC calculating code in uboot.

my K2H board use DDR K4B4G1646D-BCK0 and use below parameter to init DDR3A.

static struct ddr3_phy_config ddr3phy_1600_64A = {
    .pllcr        = 0x0001C000ul,
    .pgcr1_mask    = (IODDRM_MASK | ZCKSEL_MASK),
    .pgcr1_val    = ((1 << 2) | (1 << 7) | (1 << 23)),
    .ptr0        = 0x42C21590ul,
    .ptr1        = 0xD05612C0ul,
    .ptr2        = 0, /* not set in gel */
    .ptr3        = 0x0D861A80ul,
    .ptr4        = 0x0C827100ul,
    .dcr_mask    = (PDQ_MASK | MPRDQ_MASK | BYTEMASK_MASK),
    .dcr_val    = ((1 << 10)),
    .dtpr0        = 0xA19DBB66ul,
    .dtpr1        = 0x32868300ul,
    .dtpr2        = 0x50035200ul,
    .mr0        = 0x00001C70ul,
    .mr1        = 0x00000006ul,
    .mr2        = 0x00000018ul,
    .dtcr        = 0x710035C7ul,
    .pgcr2        = 0x00F07A12ul,
    .zq0cr1        = 0x0000005Dul,
    .zq1cr1        = 0x0000005Bul,
    .zq2cr1        = 0x0000005Bul,
    .pir_v1        = 0x00000033ul,
    .pir_v2        = 0x0000FF81ul,
};

static struct ddr3_emif_config ddr3_1600_64 = {
    //.sdcfg        = 0x6200CE6Aul,
    .sdcfg        = 0x6200CE62ul,// EBANK=0

    .sdtim1        = 0x16709C55ul,
    .sdtim2        = 0x00001D4Aul,
    .sdtim3        = 0x435DFF54ul,
    .sdtim4        = 0x553F0CFFul,
    .zqcfg        = 0xF0073200ul,
    .sdrfc        = 0x00001869ul,
};

 
those parameter are in K2H's release uboot code and I only modify .sdcfg's EBANK to 0. if my K2H board set EBANK to 1, it can not boot normally.
I have checked most DDR parameter  and they should be fitted to DDR's spec.

and the init_ddr3()'s code is below.
void init_ddr3( void ) {

    char dimm_name[32];

    if (__raw_readl(TCI6638_PLL_CNTRL_BASE + MAIN_PLL_CTRL_RSTYPE) & 0x1) {
        init_pll(&ddr3a_400);
        init_pll(&ddr3b_333);
    } else
        printf("Power-on reset was not the last reset to occur !\n");

    get_dimm_params(dimm_name);

    printf("Detected SO-DIMM [%s]\n", dimm_name);


    init_ddrphy(TCI6638_DDR3A_DDRPHYC, &ddr3phy_1600_64A);
    init_ddremif(TCI6638_DDR3A_EMIF_CTRL_BASE, &ddr3_1600_64);


    init_ddrphy(TCI6638_DDR3B_DDRPHYC, &ddr3phy_1333_64);
    init_ddremif(TCI6638_DDR3B_EMIF_CTRL_BASE, &ddr3_1333_64);

    /* Apply the workaround for PG 1.0 and 1.1 Silicons */
    if (cpu_revision() <= 1){
        ddr_reset_workaround();
    }
}

is there any idea about this issue?  where should I check in SW and HW?

  • Hi Eager,

    Have you saved the environment variables after the first boot using "saveenv" command?

    Thanks.

  • Dear Rajasekaran

    Yes, I have saved the environment variables by saveenv.

  • I add another information.

    the parameters ddr3_phy_config ddr3phy_1600_64A and ddr3_emif_config ddr3_1600_64 should be OK.

    we have another product that also use K2H and the same DDR3 chip. when I use these parameters in the board, it is fine in DDR3A 1600MHz.

  • Hi Eager,

    I don't have any suggestion to check at your end. I will work with my team and get back to you.

    Thanks.

  • Dear Rajasekaran

    I add some information for this issue.

    when the issue occur ,the log is below.


    --------------------------start

    U-Boot 2013.01 (Jun 19 2014 - 15:24:07)

    U-Boot code: 0C001000 -> 0C04C8B0  BSS: -> 0C0AFC70
    I2C:   ready
    Power-on reset was not the last reset to occur !
    Cannot read DIMM params
    Detected SO-DIMM []

    Reseting entire DDR3 memory to 0 ...
    monitor len: 000AEC70
    ramsize: 80000000
    TLB table from ffff0000 to ffff4000
    Top of RAM usable for U-Boot at: ffff0000
    Reserving 699k for U-Boot at: fff41000
    Reserving 1280k for malloc() at: ffe01000
    Reserving 32 Bytes for Board Info at: ffe00fe0
    Reserving 128 Bytes for Global Data at: ffe00f60
    New Stack Pointer is: ffe00f50
    DRAM:  2 GiB
    relocation Offset is: f3f40000

    NAND:  512 MiB

    *** Warning - bad CRC2, using default environment

    Net:   TCI6638_EMAC
    Warning: TCI6638_EMAC using MAC address from net device
    , TCI6638_EMAC1, K2HK_EMAC2 [PRIME], K2HK_EMAC3
    init_wrappers eth_initialize_r

    Hit any key to stop autoboot:  3 0
    TCI6638 EVM # crc32 0x80000000 0x100000
    CRC32 for 80000000 ... 800fffff ==> 4b1e8eeb
    TCI6638 EVM #
    CRC3TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> 781TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> e18cdbb0
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> 24025ee9
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> 8aaf6e24
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> 47379fa0
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> f37b0c92
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> 491b80d4
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffffTCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> 2b079e09
    TCI6638 EVM #

    --------------------------end


    and the issue do not occur, the log is  below.

    when the issue occur ,the log is below.
    --------------------------start

    U-Boot code: 0C001000 -> 0C04C8B0  BSS: -> 0C0AFC70
    I2C:   ready
    Cannot read DIMM params
    Detected SO-DIMM []

    Reseting entire DDR3 memory to 0 ...
    monitor len: 000AEC70
    ramsize: 80000000
    TLB table from ffff0000 to ffff4000
    Top of RAM usable for U-Boot at: ffff0000
    Reserving 699k for U-Boot at: fff41000
    Reserving 1280k for malloc() at: ffe01000
    Reserving 32 Bytes for Board Info at: ffe00fe0
    Reserving 128 Bytes for Global Data at: ffe00f60
    New Stack Pointer is: ffe00f50
    DRAM:  2 GiB
    relocation Offset is: f3f40000

    NAND:  512 MiB

    Net:   TCI6638_EMAC, TCI6638_EMAC1, K2HK_EMAC2 [PRIME], K2HK_EMAC3
    init_wrappers eth_initialize_r
    Hit any key to stop autoboot:  3 0
    TCI6638 EVM # crc32 0x80000000 0x100000
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM # crc32 0x80000000 0x100000
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM # crc32 0x80000000 0x100000
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c
    TCI6638 EVM #
    CRC32 for 80000000 ... 800fffff ==> a738ea1c

    --------------------------end

    the condition of issue can be changed after uboot run reset command.

    when the issue do not occur and I run reset command in uboot, the issue maybe occur in next boot.

    is the issue possible in DDR Leveling?

    (Unlike Keystone I devices, the controller in Keystone II devices does not require
    the user to program initial leveling values (INIT_RATIOs) to establish the starting
    point of the search window before triggering hardware leveling.)

  • Eager,

    eager hsu said:

    those parameter are in K2H's release uboot code and I only modify .sdcfg's EBANK to 0. if my K2H board set EBANK to 1, it can not boot normally.

    I have checked most DDR parameter  and they should be fitted to DDR's spec.

    I highly recommend that you check not most, but all DDR parameters from the datasheet so as to not overlook something.

    In addition, a few more questions:

    • Are you following the initialization sequence from the EVM GEL that is released as part of the MCSDK?
    • Have you verified that your board meets the layout and length matching rules?

    Please also check the PGSR0 register in the passing and failing scenarios. Leveling errors if any will be flagged in this register.

    I also had a hard time finding the datasheet for the memory part: K4B4G1646D-BCK0. Is it the same as the one on the EVM?

  • Dear Aditya

    I will check the initialization sequence from the EVM GE and let our HW check the layout and length matching rules.

    and K4B4G1646D-BCK0 is the same as EVM used.  so I think that the most parameters should be used and do not be modified in our board.

     

    thanks.

  • Dear Aditya

    about you question about 'Have you verified that your board meets the layout and length matching rules?"

    our HW say that length of DQ DQS CLK follow the table 2-28

    and the DDR layout use fly-by, you can see the below picture.

    about sw side, TI have supported emif and phy configuration for 1333MHz and 1600Mhz in UBOOT. I have check them for DDR spec and they are match.

    because we use the same DDR chip with EVM, so it should be fine.

    about PGSR0, as my observation , PGSR0 always is 0x80000fff regardless of CRC error or not. I can not use PGSR0 to judge this issue.

    about "following the initialization sequence from the EVM GEL that is released as part of the MCSDK?"

    I check ddr3B_64bit_DDR1600_setup() in the EVM GEL, it is like UBOOT's initialization sequence. but some parameters have difference(dcr_val/dtpr1/SDCFG). the SDCFG setting(0x6200CE62ul) of UBOOT should be right and dsp's(0x6700486A) is wrong. UBOOT's initialization sequence should be right.

    I add additional information, the DDR is not stable only doing CRC calculation in 1600MHz. if I do ddr test with below code, it pass.

    what can we also check in this issue?

    int ddr_memory_test(u32 start_address, u32 end_address, int quick)
    {
        u32 index_start, value, index;

        index_start = start_address;

        while (1) {
            /* Write a pattern */
            for (index = index_start;
                 index < index_start + DDR_TEST_BURST_SIZE;
                 index += 4){
                __raw_writel(index, index);
                if(index%0x8000000 == 0){
                    printf("write 0x%x\n",index);
                }
            }
            /* Read and check the pattern */
            for (index = index_start;
                 index < index_start + DDR_TEST_BURST_SIZE;
                 index += 4) {
                value = __raw_readl(index);
                if (value != index) {
                    printf("ddr_memory_test: Failed at address"
                           " index = 0x%x value = 0x%x *(index)"
                           " = 0x%x\n",
                        index, value, __raw_readl(index));
                    return -1;
                }
                if(index%0x8000000 == 0){
                    printf("read 0x%x\n",index);
                }
            }

            index_start += DDR_TEST_BURST_SIZE;
            if (index_start >= end_address)
                break;

            if (quick)
                continue;

            /* Write a pattern for complementary values */
            for (index = index_start;
                 index < index_start + DDR_TEST_BURST_SIZE;
                 index += 4){
                __raw_writel((u32)~index, index);
                if(index%0x8000000 == 0){
                    printf("write 0x%x\n",index);
                }
            }
            /* Read and check the pattern */
            for (index = index_start;
                 index < index_start + DDR_TEST_BURST_SIZE;
                 index += 4) {
                value = __raw_readl(index);
                if (value != ~index) {
                    printf("ddr_memory_test: Failed at address "
                           "index = 0x%x value = 0x%x *(index) "
                           "= 0x%x\n",
                        index, value, __raw_readl(index));
                    return -1;
                }
                if(index%0x8000000 == 0){
                    printf("read 0x%x\n",index);
                }
            }

            index_start += DDR_TEST_BURST_SIZE;
            if ((index_start >= end_address))
                break;

            /* Write a pattern */
            for (index = index_start;
                 index < index_start + DDR_TEST_BURST_SIZE;
                 index += 2){
                __raw_writew((u16)index, index);
                if(index%0x8000000 == 0){
                    printf("write 0x%x\n",index);
                }
            }
            /* Read and check the pattern */
            for (index = index_start;
                 index < index_start + DDR_TEST_BURST_SIZE;
                 index += 2) {
                value = __raw_readw(index);
                if (value != (u16)index) {
                    printf("ddr_memory_test: Failed at address "
                           "index = 0x%x value = 0x%x *(index) ="
                           " 0x%x\n",
                        index, value, __raw_readw(index));
                    return -1;
                }
                if(index%0x8000000 == 0){
                    printf("read 0x%x\n",index);
                }
            }

            index_start += DDR_TEST_BURST_SIZE;
            if ((index_start >= end_address))
                break;

            /* Write a pattern */
            for (index = index_start;
                 index < index_start + DDR_TEST_BURST_SIZE;
                 index += 1){
                __raw_writeb((u8)index, index);
                if(index%0x8000000 == 0){
                    printf("write 0x%x\n",index);
                }
            }
            /* Read and check the pattern */
            for (index = index_start;
                 index < index_start + DDR_TEST_BURST_SIZE;
                 index += 1) {
                value = __raw_readb(index);
                if (value != (u8)index) {
                    printf("ddr_memory_test: Failed at address "
                           "index = 0x%x value = 0x%x *(index) "
                           "= 0x%x\n",
                        index, value, __raw_readb(index));
                    return -1;
                }
                if(index%0x8000000 == 0){
                    printf("read 0x%x\n",index);
                }
            }

            index_start += DDR_TEST_BURST_SIZE;
            if ((index_start >= end_address))
                break;
        }

        printf("ddr_memory_test PASSED!\n");
        return 0;
    }

  • Eager,

    You PGSR0 value indiciates that initialization completed successfully and there were no leveling errors. The DDR is expected to be stable at this point and no functional read/write errors are expected.

    eager hsu said:
    the DDR is not stable only doing CRC calculation in 1600MHz. if I do ddr test with below code, it pass.

    Could you explain what is different during CRC calculation v/s the ddr_test (sorry, I am not familar with Uboot). Did the ddr test pass immediately following your failed CRC calculation or did you issue a reset in between?

    Do these problems also surface when you run DDR at 1333 MT/s?

    Regarding the length matching: do you have a table or spreadsheet showing the routed lengths from DSP to each SDRAM that proves the routing rules in the design guidelines are being met? It is just easier to review in tabular form.

  • Dear Aditya

    about difference between CRC calculation and ddr_test, I think that ddr test have less cpu loading and CRC calculation has larger cpu loading. CRC calculation have more calculation, you can see the follow code.

    I has support ddr_test function in last reply, you also can see the content.

    uint32_t ZEXPORT crc32_no_comp(uint32_t crc, const Bytef *buf, uInt len)
    {
        const uint32_t *tab = crc_table;
        const uint32_t *b =(const uint32_t *)buf;
        size_t rem_len;
    #ifdef DYNAMIC_CRC_TABLE
        if (crc_table_empty)
          make_crc_table();
    #endif
        crc = cpu_to_le32(crc);
        /* Align it */
        if (((long)b) & 3 && len) {
         uint8_t *p = (uint8_t *)b;
         do {
              DO_CRC(*p++);
         } while ((--len) && ((long)p)&3);
         b = (uint32_t *)p;
        }

        rem_len = len & 3;
        len = len >> 2;
        for (--b; len; --len) {
         /* load data 32 bits wide, xor data 32 bits wide. */
         crc ^= *++b; /* use pre increment for speed */
         DO_CRC(0);
         DO_CRC(0);
         DO_CRC(0);
         DO_CRC(0);
        }
        len = rem_len;
        /* And the last few bytes */
        if (len) {
         uint8_t *p = (uint8_t *)(b + 1) - 1;
         do {
              DO_CRC(*++p); /* use pre increment for speed */
         } while (--len);
        }

        return le32_to_cpu(crc);
    }
    # if __BYTE_ORDER == __LITTLE_ENDIAN
    #  define DO_CRC(x) crc = tab[(crc ^ (x)) & 255] ^ (crc >> 8)
    # else
    #  define DO_CRC(x) crc = tab[((crc >> 24) ^ (x)) & 255] ^ (crc << 8)
    # endif

    about the question "Do these problems also surface when you run DDR at 1333 MT/s?"

    when K2H run DDR at 1333MHz, CRC test and ddr test are fine. I never see error when DDR is at 1333MHz.  

     

    about routed lengths information, our HW will support later.

    thanks for your help.

  • Dear Aditya

    our HW support a file to you.

    Attached file is Keystone DDR3 length calculate spreadsheet based on DM81681’s form to modify.

    please check it.

    7065.DSP-XXXX DDR3_PCB_ConformanceV8.xls.

    thanks.

  • Hi Eager,

    The attached spreadsheet is not in the the form needed to determine whether the routing requirements are met. On the instructions page you have a diagram of the layout for the DDR3 memory structure. The fly-by routing of the address/command/clock signals must be length matched from the SOC to each of the memory components.  Your spreadsheet should include the following lengths for the address, command and clock signals.

    Memory 1, length of A1 + A2 + AS, Include the length of AS in a separate column since that has a separate requirement. 

    Memory 2, length of A1 + A2 + A3 + AS, Include the length of AS in a separate column since that has a separate requirement. 

    Memory 3, length of A1 + A2 + A3 + A4 + AS, Include the length of AS in a separate column since that has a separate requirement. 

    Memory 4, length of A1 + A2 + A3 + A4 + A5 + AS, Include the length of AS in a separate column since that has a separate requirement.  Note that A5 is shown as A3 in the diagram.

    Even without the lengths in this form I can tell that the routing does not meet the published requirements. The address and command signals much be length matched relative to the clock with the following requirement.

    All nets in the address and command fly-by groups must be length-matched from the controller to each SDRAM separately within +/- 20 mils of the clock along the same route.


    The skew between the clock and the address/command for the first memory has a skew value of 388.51 mils. This is probably why the interface can't operate at 1600.

    Regards, Bill

  • Dear Bill

    thanks for your reply, I will tell our HW to check this point.

  • eager-san,

    Finally, can you see the DDR3A operation with 1600 datarate in K2HEVM?
    I would like to know if it is operated correctly.

    Best regards, RY

  • Dear RY9983

    it should operate correctly now.

    our HW do some modification to reduce the probability of DDR error.

    and I add a DDR check in uboot to check DDR is normal or not. (it is for double check.)

    if DDR is abnormality, uboot will reset.

    thanks.

  • eager-san,

    Thanks so much for your update. It's helpful for me.

    Best regards RY