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.

Flat Access To DDR3 on AM335x

I'm trying to kick out a simple (ha ha!) assembly language project in
which I perform some simple DRAM tests on board based on the TI AM3352
using a 512 MB DRAM (256M x 16). 

Ideally I'd like to just treat DRAM as a flat address space from
0x80000000 to 0x82000000.

  1. Can I just "turn off" the MMU?

  2. Should I keep data cache turned off as well?

  3. Are there any access sequence restrictions? E.g., can I just
  read/write each 16-bit value sequentially?

  4. Any other gotchas?

I believe I've got the EMIF/DDR3 controller initialized properly (I used
the u-boot code for the beaglebone black), but I can't get the test code
proper running. I'm getting DABORT exceptions on the _second_ time
through the write loop in the following code.

Any help would be appreciated.

--Randy


#include "asm-defs/asm-defs.h"
#include "asm-defs/prcm.h"
#include "asm-defs/emif.h"
#include "asm-defs/control.h"
#include "asm-defs/cm.h"

                .cpu        cortex-a8
                .text

//----------------------------------------
// Randy Yates
// 
// entry:
//   ro = base of DRAM test. must be even since DRAM is 16-bit words
//   r2 = count of 16-bit words to test
//   r3 = value to write (lower 16-bits)

// routine usage
//   r1 = current offset into r0 (base of dram test)
//   r4 = value read back

// return:
//   r7 = result (boolean: test successful)
//              0x01 = test passed
//              0x00 = test failed
//----------------------------------------

.fun ddr3_value_test
                push        {lr}

                mov         r1, 0

// first write all values
ddr3_value_test_write_loop:
                str.n       r3, [r0, r1]                // <== DABORT error here on second time through the loop 
                add         r1, #2
                subs        r2, #1
                bne         ddr3_value_test_write_loop

// now read back values
                mov         r1, 0
ddr3_value_test_read_loop:
                ldr.n       r4, [r0, r1]
                subs        r4, r3
                bne         ddr3_value_test_fail

                add         r1, #2
                subs        r2, #1
                bne         ddr3_value_test_read_loop

// test passed:
                mov         r7, 0x01
                pop         {pc}

// test failed:
ddr3_value_test_fail:
                mov         r7, 0
                pop         {pc}

  • Hi Randy,

    Yes, you can turn off the MMU and caches for testing. However make sure your code is loaded and running from internal SRAM, otherwise it may get overwritten by the test patterns.
  • Biser,

    Thanks for the clarification. But why does this code generate a DABORT exception?

    --Randy
  • PS: One thought I've had is that if the EMIF/DDR3 is not initialized properly, then an access to DRAM might generate this type of error.

    Thus I'm including the DRAM initialization code (taken from u-boot) as follows. Please let me know if there are any errors or omissions.

    --Randy

    #include "asm-defs/asm-defs.h"
    #include "asm-defs/prcm.h"
    #include "asm-defs/emif.h"
    #include "asm-defs/control.h"
    #include "asm-defs/cm.h"

    .cpu cortex-a8
    .text

    #define DDR_CKE_CTRL_NORMAL 0x1

    //----------------------------------------
    // TIME firmware DDR3 DRAM initialization
    // Randy Yates
    //
    // Note that this initialization code is
    // taken from the u-boot initialization
    // code. the c calls from there are shown
    // in the comments.
    //
    // the main u-boot routine is arch/arm/cpu/armv7/am33xx/emif4.c:config_ddr().
    // it is called from board/ti/am335x/board.c:sdram_init() as follows
    //
    // config_ddr(400, &ioregs_bonelt,
    // &ddr3_beagleblack_data,
    // &ddr3_beagleblack_cmd_ctrl_data,
    // &ddr3_beagleblack_emif_reg_data, 0);
    //
    //----------------------------------------

    // r0 = destroyed
    // r1 = destroyed
    // r2 = destroyed
    // r4 = interrupt controller (do not destroy)

    .fun ddr3_init
    push {lr}

    // enable clock domains PD_PER_L3_GCLK (OCP) and PD_PER_EMIF_GCLK (Func), which are part of the CM_PER_L3_CLKSTCTRL register

    ldr r0, cm_per_base
    // ldr r1, [ r0, CM_PER_L3_CLKSTCTRL_OFFSET ]
    // orr r1, CM_PER_L3_CLKSTCTRL_L3_GCLK
    // orr r1, CM_PER_L3_CLKSTCTRL_EMIF_GCLK
    // str r1, [ r0, CM_PER_L3_CLKSTCTRL_OFFSET ]

    // Note: this is taken from the CCSV6.1.2 beagleboneblack.gel file (/opt/ti/ccsv6/ccs_base/emulation/boards/beaglebone/gel/beagleboneblack.gel)

    mov r1, 0x02
    str r1, [r0, CM_PER_EMIF_CLKCTRL_OFFSET]

    ddr3_init_l0:
    ldr r1, [r0, CM_PER_EMIF_CLKCTRL_OFFSET]
    subs r1, #0x02
    bne ddr3_init_l0


    //void config_ddr(unsigned int pll, const struct ctrl_ioregs *ioregs,
    // const struct ddr_data *data, const struct cmd_control *ctrl,
    // const struct emif_regs *regs, int nr)
    //{
    // ddr_pll_config(pll);
    //#ifndef CONFIG_TI816X
    // config_vtp(nr);
    //#endif
    // config_cmd_ctrl(ctrl, nr);
    //
    // config_ddr_data(data, nr);
    //#ifdef CONFIG_AM33XX
    // config_io_ctrl(ioregs);
    //
    // /* Set CKE to be controlled by EMIF/DDR PHY */
    // writel(DDR_CKE_CTRL_NORMAL, &ddrctrl->ddrckectrl);
    //
    //#endif
    //#ifdef CONFIG_AM43XX
    // writel(readl(&cm_device->cm_dll_ctrl) & ~0x1, &cm_device->cm_dll_ctrl);
    // while ((readl(&cm_device->cm_dll_ctrl) & CM_DLL_READYST) == 0)
    // ;
    //
    // config_io_ctrl(ioregs);
    //
    // /* Set CKE to be controlled by EMIF/DDR PHY */
    // writel(DDR_CKE_CTRL_NORMAL, &ddrctrl->ddrckectrl);
    //
    // if (emif_sdram_type(regs->sdram_config) == EMIF_SDRAM_TYPE_DDR3)
    // /* Allow EMIF to control DDR_RESET */
    // writel(0x00000000, &ddrctrl->ddrioctrl);
    //#endif
    //
    // /* Program EMIF instance */
    // config_ddr_phy(regs, nr);
    // set_sdram_timings(regs, nr);
    // if (get_emif_rev(EMIF1_BASE) == EMIF_4D5)
    // config_sdram_emif4d5(regs, nr);
    // else
    // config_sdram(regs, nr);
    //}

    // ddr_pll_config(400);
    // Note: I thought this was not necessary (see section 26.1.4.3 of the trm, which says the ROM code configures the ddr pll to 400 MHz) but Matt van Duin
    // found via some code he write that the DDR PLL is indeed not configured or enabled at the end of the public ROM code
    bl config_ddr_pll

    // config_vtp(nr); nr is the emif interface number and is set to 0.
    bl config_vtp

    // config_cmd_ctrl(ctrl, nr);
    bl config_cmd_ctrl

    // config_ddr_data(data, nr);
    bl config_ddr_data

    // config_io_ctrl(ioregs);
    bl config_io_ctrl

    // /* Set CKE to be controlled by EMIF/DDR PHY */
    // writel(DDR_CKE_CTRL_NORMAL, &ddrctrl->ddrckectrl);
    ldr r0, control_module_base
    mov r1, DDR_CKE_CTRL_NORMAL
    str r1, [r0, CONTROL_DDR_IO_CTRL_OFFSET]

    // config_ddr_phy(regs, nr);
    bl config_ddr_phy
    // pop {pc}

    // set_sdram_timings(regs, nr);
    bl set_sdram_timings

    // config_sdram(regs, nr);
    bl config_sdram

    pop {pc}


    //
    //------------------
    // config_ddr_pll
    //------------------
    //

    // The DDR PLL output frequency is given by F = ((F_CLKINP / (N + 1)) * M) / M2,
    //
    // where
    // F_CLKINPUT = system oscillator input frequency (24 MHz)
    // N = CM_CLKSEL_DPLL_DDR.DPLL_DIV
    // M = CM_CLKSEL_DPLL_DDR.DPLL_MULT
    // M2 = CM_DIV_M2_DPLL_DDIR.DPLL_CLKOUT_DIV
    //
    // We want F to be 400 MHz, so let N = 23, M = 400, M2 = 1
    //
    // am335x trm reference: section 8.1.6.3 and figure 8-8, and section 8.1.6.11 and figure 8-14.
    //
    .fun config_ddr_pll
    push {lr}

    ldr r0, cm_wkup_base

    // switch PLL to bypass
    ldr r1, [r0, CM_WKUP_CLKMODE_DPLL_DDR]
    and r1, 0xfffffff8
    orr r1, 0x04
    str r1, [r0, CM_WKUP_CLKMODE_DPLL_DDR]

    // wait for PLL to go to bypass
    config_ddr_pll_l0:
    ldr r1, [r0, CM_WKUP_IDLEST_DPLL_DDR]
    ands r1, 0x0100
    beq config_ddr_pll_l0

    // configure N and M
    mov r1, 400 << 8 // set the DPLL_BYP_CLKSEL to 0 and M to 400
    orr r1, 23 // set N to 23
    str r1, [r0, CM_WKUP_CLKSEL_DPLL_DDR]

    // configure M2
    mov r1, 1
    str r1, [r0, CM_WKUP_DIV_M2_DPLL_DDR]

    // switch pll to lock mode
    ldr r1, [r0, CM_WKUP_CLKMODE_DPLL_DDR]
    and r1, 0xfffffff8
    orr r1, 0x07
    str r1, [r0, CM_WKUP_CLKMODE_DPLL_DDR]

    // wait for pll to lock
    config_ddr_pll_l1:
    ldr r1, [r0, CM_WKUP_IDLEST_DPLL_DDR]
    ands r1, 0x0001
    beq config_ddr_pll_l1

    pop {pc}

    //
    //------------------
    // config_vtp
    //------------------
    //
    .fun config_vtp
    push {lr}
    ldr r0, vtp0_ctrl_addr
    // writel(readl(&vtpreg[nr]->vtp0ctrlreg) | VTP_CTRL_ENABLE,
    // &vtpreg[nr]->vtp0ctrlreg);
    ldr r1, [r0]

    orr r1, EMIF_VTP_CTRL_ENABLE
    str r1, [r0]

    // writel(readl(&vtpreg[nr]->vtp0ctrlreg) & (~VTP_CTRL_START_EN),
    // &vtpreg[nr]->vtp0ctrlreg);
    ldr r1, [r0]
    and r1, ~EMIF_VTP_CTRL_START_EN
    str r1, [r0]

    // writel(readl(&vtpreg[nr]->vtp0ctrlreg) | VTP_CTRL_START_EN,
    // &vtpreg[nr]->vtp0ctrlreg);
    ldr r1, [r0]
    orr r1, EMIF_VTP_CTRL_START_EN
    str r1, [r0]

    // /* Poll for READY */
    // while ((readl(&vtpreg[nr]->vtp0ctrlreg) & VTP_CTRL_READY) !=
    // VTP_CTRL_READY)
    // ;
    config_vtp_l0:
    ldr r1, [r0]
    and r1, EMIF_VTP_CTRL_READY
    beq config_vtp_l0

    pop {pc}

    //
    //------------------
    // config_cmd_ctrl
    //------------------
    //
    //static const struct cmd_control ddr3_beagleblack_cmd_ctrl_data = {
    // .cmd0csratio = MT41K256M16HA125E_RATIO,
    // .cmd0iclkout = MT41K256M16HA125E_INVERT_CLKOUT,
    //
    // .cmd1csratio = MT41K256M16HA125E_RATIO,
    // .cmd1iclkout = MT41K256M16HA125E_INVERT_CLKOUT,
    //
    // .cmd2csratio = MT41K256M16HA125E_RATIO,
    // .cmd2iclkout = MT41K256M16HA125E_INVERT_CLKOUT,
    //};
    //
    ///**
    // * Configure DDR CMD control registers
    // */
    //void config_cmd_ctrl(const struct cmd_control *cmd, int nr)
    //{
    // if (!cmd)
    // return;
    //
    // writel(cmd->cmd0csratio, &ddr_cmd_reg[nr]->cm0csratio);
    // writel(cmd->cmd0iclkout, &ddr_cmd_reg[nr]->cm0iclkout);
    //
    // writel(cmd->cmd1csratio, &ddr_cmd_reg[nr]->cm1csratio);
    // writel(cmd->cmd1iclkout, &ddr_cmd_reg[nr]->cm1iclkout);
    //
    // writel(cmd->cmd2csratio, &ddr_cmd_reg[nr]->cm2csratio);
    // writel(cmd->cmd2iclkout, &ddr_cmd_reg[nr]->cm2iclkout);
    //}

    .fun config_cmd_ctrl
    push {lr}

    ldr r0, ddr_phy_cmd_addr_base

    // writel(cmd->cmd0csratio, &ddr_cmd_reg[nr]->cm0csratio);
    ldr r1, MT41K256M16HA125E_RATIO
    str r1, [ r0, EMIF_DDR_CMD0_REG_PHY_CTRL_SLAVE_RATIO_OFFSET ]

    // writel(cmd->cmd0iclkout, &ddr_cmd_reg[nr]->cm0iclkout);
    ldr r1, MT41K256M16HA125E_INVERT_CLKOUT
    str r1, [ r0, EMIF_DDR_CMD0_REG_PHY_INVERT_CLKOUT_OFFSET ]

    // writel(cmd->cmd1csratio, &ddr_cmd_reg[nr]->cm1csratio);
    ldr r1, MT41K256M16HA125E_RATIO
    str r1, [ r0, EMIF_DDR_CMD1_REG_PHY_CTRL_SLAVE_RATIO_OFFSET ]

    // writel(cmd->cmd1iclkout, &ddr_cmd_reg[nr]->cm1iclkout);
    ldr r1, MT41K256M16HA125E_INVERT_CLKOUT
    str r1, [ r0, EMIF_DDR_CMD1_REG_PHY_INVERT_CLKOUT_OFFSET ]

    // writel(cmd->cmd2csratio, &ddr_cmd_reg[nr]->cm2csratio);
    ldr r1, MT41K256M16HA125E_RATIO
    str r1, [ r0, EMIF_DDR_CMD2_REG_PHY_CTRL_SLAVE_RATIO_OFFSET ]

    // writel(cmd->cmd2iclkout, &ddr_cmd_reg[nr]->cm2iclkout);
    ldr r1, MT41K256M16HA125E_INVERT_CLKOUT
    str r1, [ r0, EMIF_DDR_CMD2_REG_PHY_INVERT_CLKOUT_OFFSET ]

    pop {pc}

    //
    //------------------
    // config_ddr_data
    //------------------
    //
    ///**
    // * Configure DDR DATA registers
    // */
    //void config_ddr_data(const struct ddr_data *data, int nr)
    //{
    // int i;
    //
    // if (!data)
    // return;
    //
    // for (i = 0; i < DDR_DATA_REGS_NR; i++) {
    // writel(data->datardsratio0,
    // &(ddr_data_reg[nr]+i)->dt0rdsratio0);
    // writel(data->datawdsratio0,
    // &(ddr_data_reg[nr]+i)->dt0wdsratio0);
    // writel(data->datawiratio0,
    // &(ddr_data_reg[nr]+i)->dt0wiratio0);
    // writel(data->datagiratio0,
    // &(ddr_data_reg[nr]+i)->dt0giratio0);
    // writel(data->datafwsratio0,
    // &(ddr_data_reg[nr]+i)->dt0fwsratio0);
    // writel(data->datawrsratio0,
    // &(ddr_data_reg[nr]+i)->dt0wrsratio0);
    // }
    //}
    //static const struct ddr_data ddr3_beagleblack_data = {
    // .datardsratio0 = MT41K256M16HA125E_RD_DQS,
    // .datawdsratio0 = MT41K256M16HA125E_WR_DQS,
    // .datafwsratio0 = MT41K256M16HA125E_PHY_FIFO_WE,
    // .datawrsratio0 = MT41K256M16HA125E_PHY_WR_DATA,
    //};

    .fun config_ddr_data
    push {lr}

    // note we do things a bit differently here than in the u-boot code, which separates
    // cmd and data pointers, we just use one pointer, defined above

    ldr r0, ddr_phy_cmd_addr_base

    // writel(data->datardsratio0,
    // &(ddr_data_reg[nr]+i)->dt0rdsratio0);
    ldr r1, MT41K256M16HA125E_RD_DQS
    str r1, [ r0, EMIF_DDR_DATA0_REG_PHY_RD_DQS_SLAVE_RATIO_OFFSET ]

    // writel(data->datawdsratio0,
    // &(ddr_data_reg[nr]+i)->dt0wdsratio0);
    ldr r1, MT41K256M16HA125E_WR_DQS
    str r1, [ r0, EMIF_DDR_DATA0_REG_PHY_WR_DQS_SLAVE_RATIO_OFFSET ]

    // writel(data->datawiratio0,
    // &(ddr_data_reg[nr]+i)->dt0wiratio0);
    eor r1, r1
    str r1, [ r0, EMIF_DDR_DATA0_REG_PHY_WRLVL_INIT_RATIO_OFFSET ]

    // writel(data->datagiratio0,
    // &(ddr_data_reg[nr]+i)->dt0giratio0);
    eor r1, r1
    str r1, [ r0, EMIF_DDR_DATA0_REG_PHY_GATELVL_INIT_RATIO_OFFSET ]

    // writel(data->datafwsratio0,
    // &(ddr_data_reg[nr]+i)->dt0fwsratio0);
    ldr r1, MT41K256M16HA125E_PHY_FIFO_WE
    str r1, [ r0, EMIF_DDR_DATA0_REG_PHY_FIFO_WE_SLAVE_RATIO_OFFSET ]

    // writel(data->datawrsratio0,
    // &(ddr_data_reg[nr]+i)->dt0wrsratio0);
    ldr r1, MT41K256M16HA125E_PHY_WR_DATA
    str r1, [ r0, EMIF_DDR_DATA0_REG_PHY_WR_DATA_SLAVE_RATIO_OFFSET ]

    pop {pc}

    //
    //------------------
    // config_io_ctrl
    //------------------
    //
    ///home/u-boot/arch/arm/cpu/armv7/am33xx/ddr.c
    //void config_io_ctrl(const struct ctrl_ioregs *ioregs)
    //{
    // if (!ioregs)
    // return;
    //
    // writel(ioregs->cm0ioctl, &ioctrl_reg->cm0ioctl);
    // writel(ioregs->cm1ioctl, &ioctrl_reg->cm1ioctl);
    // writel(ioregs->cm2ioctl, &ioctrl_reg->cm2ioctl);
    // writel(ioregs->dt0ioctl, &ioctrl_reg->dt0ioctl);
    // writel(ioregs->dt1ioctl, &ioctrl_reg->dt1ioctl);
    //#ifdef CONFIG_AM43XX
    // writel(ioregs->dt2ioctrl, &ioctrl_reg->dt2ioctrl);
    // writel(ioregs->dt3ioctrl, &ioctrl_reg->dt3ioctrl);
    // writel(ioregs->emif_sdram_config_ext,
    // &ioctrl_reg->emif_sdram_config_ext);
    //#endif
    //}

    .fun config_io_ctrl
    push {lr}

    ldr r0, control_module_ddr_base

    // writel(ioregs->cm0ioctl, &ioctrl_reg->cm0ioctl);
    ldr r1, MT41K256M16HA125E_IOCTRL_VALUE
    str r1, [r0, CONTROL_CMD0_IOCTRL_OFFSET]

    // writel(ioregs->cm1ioctl, &ioctrl_reg->cm1ioctl);
    ldr r1, MT41K256M16HA125E_IOCTRL_VALUE
    str r1, [r0, CONTROL_CMD1_IOCTRL_OFFSET]

    // writel(ioregs->cm2ioctl, &ioctrl_reg->cm2ioctl);
    ldr r1, MT41K256M16HA125E_IOCTRL_VALUE
    str r1, [r0, CONTROL_CMD2_IOCTRL_OFFSET]

    // writel(ioregs->dt0ioctl, &ioctrl_reg->dt0ioctl);
    ldr r1, MT41K256M16HA125E_IOCTRL_VALUE
    str r1, [r0, CONTROL_DATA0_IOCTRL_OFFSET]

    // writel(ioregs->dt1ioctl, &ioctrl_reg->dt1ioctl);
    ldr r1, MT41K256M16HA125E_IOCTRL_VALUE
    str r1, [r0, CONTROL_DATA1_IOCTRL_OFFSET]

    pop {pc}

    //
    //------------------
    // config_ddr_phy
    //------------------
    //
    //void config_ddr_phy(const struct emif_regs *regs, int nr)
    //{
    // /*
    // * Disable initialization and refreshes for now until we
    // * finish programming EMIF regs.
    // * Also set time between rising edge of DDR_RESET to rising
    // * edge of DDR_CKE to > 500us per memory spec.
    // */
    //#ifndef CONFIG_AM43XX (no, this is not CONFIG_AM43XX)
    // setbits_le32(&emif_reg[nr]->emif_sdram_ref_ctrl,
    // EMIF_REG_INITREF_DIS_MASK);
    //#endif
    // if (regs->zq_config) (yes, zq_config is non-zero)
    // /* Set time between rising edge of DDR_RESET to rising
    // * edge of DDR_CKE to > 500us per memory spec. */
    // writel(0x00003100, &emif_reg[nr]->emif_sdram_ref_ctrl);
    //
    // writel(regs->emif_ddr_phy_ctlr_1,
    // &emif_reg[nr]->emif_ddr_phy_ctrl_1);
    // writel(regs->emif_ddr_phy_ctlr_1,
    // &emif_reg[nr]->emif_ddr_phy_ctrl_1_shdw);
    //
    // if (get_emif_rev((u32)emif_reg[nr]) == EMIF_4D5) {
    // if (emif_sdram_type(regs->sdram_config) == EMIF_SDRAM_TYPE_DDR3)
    // ext_phy_settings_hwlvl(regs, nr);
    // else
    // ext_phy_settings_swlvl(regs, nr);
    // }
    //}

    .fun config_ddr_phy
    push {lr}

    ldr r0, emif_base

    // setbits_le32(&emif_reg[nr]->emif_sdram_ref_ctrl,
    // EMIF_REG_INITREF_DIS_MASK);
    ldr r1, [r0, EMIF_SDRAM_REF_CTRL_OFFSET]
    // pop {pc}
    orr r1, 1 << 31
    str r1, [r0, EMIF_SDRAM_REF_CTRL_OFFSET]

    // writel(0x00003100, &emif_reg[nr]->emif_sdram_ref_ctrl);
    movs r1, 0x3100
    str r1, [r0, EMIF_SDRAM_REF_CTRL_OFFSET]

    // writel(regs->emif_ddr_phy_ctlr_1,
    // &emif_reg[nr]->emif_ddr_phy_ctrl_1);
    ldr r1, MT41K256M16HA125E_EMIF_READ_LATENCY
    str r1, [r0, EMIF_SDRAM_DDR_PHY_CTRL_1_OFFSET]

    // writel(regs->emif_ddr_phy_ctlr_1,
    // &emif_reg[nr]->emif_ddr_phy_ctrl_1_shdw);
    str r1, [r0, EMIF_SDRAM_DDR_PHY_CTRL_1_SHDW_OFFSET]

    // this is NOT EMIF_4D5 (major rev 5), but rather major rev 4

    pop {pc}

    //
    //------------------
    // set_sdram_timings
    //------------------
    //
    //void set_sdram_timings(const struct emif_regs *regs, int nr)
    //{
    // writel(regs->sdram_tim1, &emif_reg[nr]->emif_sdram_tim_1);
    // writel(regs->sdram_tim1, &emif_reg[nr]->emif_sdram_tim_1_shdw);
    // writel(regs->sdram_tim2, &emif_reg[nr]->emif_sdram_tim_2);
    // writel(regs->sdram_tim2, &emif_reg[nr]->emif_sdram_tim_2_shdw);
    // writel(regs->sdram_tim3, &emif_reg[nr]->emif_sdram_tim_3);
    // writel(regs->sdram_tim3, &emif_reg[nr]->emif_sdram_tim_3_shdw);
    //}

    .fun set_sdram_timings
    push {lr}

    // writel(regs->sdram_tim1, &emif_reg[nr]->emif_sdram_tim_1);
    ldr r1, MT41K256M16HA125E_EMIF_TIM1
    str r1, [r0, EMIF_SDRAM_TIM_1_OFFSET]

    // writel(regs->sdram_tim1, &emif_reg[nr]->emif_sdram_tim_1_shdw);
    str r1, [r0, EMIF_SDRAM_TIM_1_SHDW_OFFSET]

    // writel(regs->sdram_tim2, &emif_reg[nr]->emif_sdram_tim_2);
    ldr r1, MT41K256M16HA125E_EMIF_TIM2
    str r1, [r0, EMIF_SDRAM_TIM_2_OFFSET]

    // writel(regs->sdram_tim2, &emif_reg[nr]->emif_sdram_tim_2_shdw);
    str r1, [r0, EMIF_SDRAM_TIM_2_SHDW_OFFSET]

    // writel(regs->sdram_tim3, &emif_reg[nr]->emif_sdram_tim_3);
    ldr r1, MT41K256M16HA125E_EMIF_TIM3
    str r1, [r0, EMIF_SDRAM_TIM_3_OFFSET]

    // writel(regs->sdram_tim3, &emif_reg[nr]->emif_sdram_tim_3_shdw);
    str r1, [r0, EMIF_SDRAM_TIM_3_SHDW_OFFSET]

    pop {pc}

    //
    //------------------
    // config_sdram
    //------------------
    // <u-boot>/arch/arm/cpu/armv7/am33xx/ddr.c:161:
    //void config_sdram(const struct emif_regs *regs, int nr)
    //{
    // if (regs->zq_config) {
    // writel(regs->zq_config, &emif_reg[nr]->emif_zq_config);
    // writel(regs->sdram_config, &cstat->secure_emif_sdram_config);
    // writel(regs->sdram_config, &emif_reg[nr]->emif_sdram_config);
    //
    // /* Trigger initialization */
    // writel(0x00003100, &emif_reg[nr]->emif_sdram_ref_ctrl);
    // /* Wait 1ms because of L3 timeout error */
    // udelay(1000);
    //
    // /* Write proper sdram_ref_cref_ctrl value */
    // writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl);
    // writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl_shdw);
    // }
    // writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl);
    // writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl_shdw);
    // writel(regs->sdram_config, &emif_reg[nr]->emif_sdram_config);
    //}

    .fun config_sdram
    push {lr}

    ldr r0, emif_base

    // writel(regs->zq_config, &emif_reg[nr]->emif_zq_config);
    ldr r1, MT41K256M16HA125E_ZQ_CFG
    str r1, [r0, EMIF_SDRAM_ZQ_CONFIG_OFFSET]

    // writel(regs->sdram_config, &cstat->secure_emif_sdram_config);
    ldr r2, control_module_base
    ldr r1, MT41K256M16HA125E_EMIF_SDCFG
    str r1, [r2, CONTROL_EMIF_SDRAM_CONFIG_OFFSET]

    // writel(regs->sdram_config, &emif_reg[nr]->emif_sdram_config);
    str r1, [r0, EMIF_SDRAM_CONFIG_OFFSET]

    // /* Trigger initialization */
    // writel(0x00003100, &emif_reg[nr]->emif_sdram_ref_ctrl);
    movs r1, 0x3100
    str r1, [r0, EMIF_SDRAM_REF_CTRL_OFFSET]

    // /* Wait 1ms because of L3 timeout error */
    // udelay(1000);
    ldr r3, ONE_MILLISECOND_DELAY
    bl udelay

    // /* Write proper sdram_ref_cref_ctrl value */
    // writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl);
    ldr r1, MT41K256M16HA125E_EMIF_SDREF
    str r1, [r0, EMIF_SDRAM_REF_CTRL_OFFSET]

    // writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl_shdw);
    str r1, [r0, EMIF_SDRAM_REF_CTRL_SHDW_OFFSET]

    // writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl);
    str r1, [r0, EMIF_SDRAM_REF_CTRL_OFFSET]

    // writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl_shdw);
    str r1, [r0, EMIF_SDRAM_REF_CTRL_SHDW_OFFSET]

    // writel(regs->sdram_config, &emif_reg[nr]->emif_sdram_config);
    ldr r1, MT41K256M16HA125E_EMIF_SDCFG
    str r1, [r0, EMIF_SDRAM_CONFIG_OFFSET]

    pop {pc}

    //
    //---------------------------------------------------------------------------
    // udelay - delay specified number of microseconds. delay value passed in r3
    // (note: this is approximate). r2 is destroyed
    //---------------------------------------------------------------------------
    //
    .fun udelay
    push {lr}

    udelay_l0:
    ldr r2, ONE_MICROSECOND_DELAY

    udelay_l1:
    subs r2, #1
    bne udelay_l1

    subs r3, #1
    bne udelay_l0

    pop {pc}

    //--------------
    // module data
    //--------------

    // memory map offsets

    .var cm_per_base
    .word 0x44e00000

    .var cm_wkup_base
    .word 0x44e00400

    .var emif_base
    .word 0x4c000000

    .var control_module_base
    .word 0x44e10000

    .var control_module_ddr_base
    .word 0x44e11404

    .var vtp0_ctrl_addr
    .word 0x44e10e0c

    .var ddr_phy_cmd_addr_base
    .word 0x44E12000

    // data that is too big for an immediate mov rn, data and must use a ldr rn, pc-relative-data instead:

    .var MT41K256M16HA125E_IOCTRL_VALUE
    .word 0x018B

    .var MT41K256M16HA125E_RD_DQS
    .word 0x38

    .var MT41K256M16HA125E_WR_DQS
    .word 0x44

    .var MT41K256M16HA125E_PHY_WR_DATA
    .word 0x7D

    .var MT41K256M16HA125E_PHY_FIFO_WE
    .word 0x94

    .var MT41K256M16HA125E_EMIF_READ_LATENCY
    .word 0x100007

    .var MT41K256M16HA125E_EMIF_TIM1
    .word 0x0AAAD4DB

    .var MT41K256M16HA125E_EMIF_TIM2
    .word 0x266B7FDA

    .var MT41K256M16HA125E_EMIF_TIM3
    .word 0x501F867F

    .var MT41K256M16HA125E_EMIF_SDCFG
    .word 0x61C05332

    .var MT41K256M16HA125E_EMIF_SDREF
    .word 0xC30

    .var MT41K256M16HA125E_ZQ_CFG
    .word 0x50074BE4

    .var MT41K256M16HA125E_RATIO
    .word 0x80

    .var MT41K256M16HA125E_INVERT_CLKOUT
    .word 0x0

    .var ONE_MILLISECOND_DELAY
    .word 1000

    .var ONE_MICROSECOND_DELAY
    .word 32000
  • I can't say, I'm not a software expert and this forum supports the Linux SDK only.
  • I did not realize this forum was only for linux. I could not find another forum that dealt with Sitara processors. Can you suggest the proper forum?
  • A question: Is this a custom board? If it is, here are the guidelines for DDR EMIF configuration:

    processors.wiki.ti.com/.../AM335x_EMIF_Configuration_tips
    processors.wiki.ti.com/.../AM335x_DDR_PHY_register_configuration_for_DDR3

    The DDR won't run properly unless these configuration steps are done first.
  • Another suggestion is that you take the Starterware bootloader as a base for your initialization: software-dl.ti.com/.../index_FDS.html
  • Randy Yates said:
    why does this code generate a DABORT exception?

    Because it performs misaligned accesses, which are not permitted when the MMU is disabled (or more generally to Device or Strongly-Ordered memory, the latter being the default for all memory access when the MMU is disabled).

    You probably meant to use strh / ldrh. (The ".n" suffix demands a 16-bit instruction encoding, and is redundant since the assembler will prefer such encoding whenever possible.)

    One thought I've had is that if the EMIF/DDR3 is not initialized properly, then an access to DRAM might generate this type of error.

    I've never seen EMIF return errors unless
    - it is disabled entirely (in which case the error is technically returned by its L3 target agent), or
    - an unsupported burst type is used (EDMA's "fifo mode").

    I doubt whether incorrect initialization is capable of making it return errors. In most cases it actually has no way of knowing something is wrong.

    Can I just "turn off" the MMU?

    The MMU is off by default; turning it off after it has been turned on can actually be quite tricky and at least requires cleaning and invalidating caches.

    Should I keep data cache turned off as well?

    Data cache is always implicitly off when the MMU is disabled, since all data accesses are Strongly-Ordered. The 'C'-bit of the system control register should however always be kept off while the MMU is off to prevent erratic behaviour.

    Are there any access sequence restrictions?

    Access to Device and Strongly-Ordered memory must have appropriate alignment. If I recall correctly min(access size, 32-bit) alignment suffices (except for ldrexd/strexd).

    Can I just read/write each 16-bit value sequentially?

    Why 16-bit? This is not a native size for any component along the way. The data path from cortex-A8 to EMIF is 128-bit (16-byte) wide all the way. Also, DDR3 reads/writes are always 8-cycle bursts, which in case of a 16-bit DDR3 data bus means any access results in one or more aligned 16-byte transfers. Any access smaller than 16 bytes just means the unused bytes are discarded (for reads) or masked (for writes).

    Any other gotchas?

    Strongly-ordered accesses are very slow. Your fill loop will probably be about 100 times slower than necessary. (Uncacheable reads of any sort are also, except Neon loads from Normal uncacheable memory).

    Also, your memory test is a very poor one and may pass even in the presence of serious memory faults. For low count it may even pass if the memory is entirely inoperable simply due to the 16-bit value being held capacitively on the data bus (I've actually seen this happen once a long time ago on some board, though this was with a loop that performed a single write followed by a single read.)

  • Matt,

    Thank you for the answer and other hints. The root fault was simply that I misread the docs to mean ldr.n/str.n meant a narrow (16-bit) read, and instead should have used ldrh/strh (halfword) is the correct instruction.

    Regarding your comment on the memory test being a poor one, it wasn't intended to be a good memory test but more of a "is this code running correctly" test.
  • Biser, thank you as well for your comments and suggestions.