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.

Linux/AM4376: DDR3 access issue

Part Number: AM4376

Tool/software: Linux

Hello community

We can't use the full 32 bit of DDR3 RAM in our custom board. The schematic based on the schematic of the AM437x Industrial Development Kit (IDK). Instead of the two MT41K256M16HA we use two AS4C64M16D3A-12BIN DDR3 RAM banks and a 25MHz oscillator.

To startup the linux kernel we use TI U-Boot (branch ti-u-boot-2017.01) and added there a custom board to do the PLL and the DDR settings. The U-Boot board are an adaption of the am43xx board. With the AM43xx DDR Calculation tool (.zip) I got following register values:

static const struct emif_regs ddr3_leu150_emif_regs_400Mhz = {
.sdram_config              = 0x61A11A32,
.sdram_config2            = 0x00000000,
.ref_ctrl                         = 0x00000c30,
.sdram_tim1                 = 0xEAAAD4D3,
.sdram_tim2                 = 0x282F7FD2,
.sdram_tim3                 = 0x507F82B8,
.read_idle_ctrl               = 0x00050000,
.zq_config                     = 0x50074be4,
.temp_alert_config        = 0x00000000,
.emif_ddr_phy_ctlr_1   = 0x00008009,
...
};

With this settings the U-Boot SPL won't start from the SD card and there are no output on the serial console. If I switch to the 16 Bit mode (.sdram_config = 0x61A15A32) the U-Boot SPL is starting and even the U-Boot starts. But only the half of the DDR3 RAM (128 MB) can be accessed. So I think the calculated DDR timing is correct. The layout looks good and according to the guidelines. So I have no idea what could be wrong.

I'm thankful for any hint, thank you very much.

Cheers
Thomas

  • The DDR experts have been notified. They will respond here.
  • Thank you!

    I added my U-Boot code and the DDR timing calculation sheet also.

    #include <common.h>
    #include <i2c.h>
    #include <linux/errno.h>
    #include <spl.h>
    #include <usb.h>
    #include <asm/omap_sec_common.h>
    #include <asm/arch/clock.h>
    #include <asm/arch/sys_proto.h>
    #include <asm/arch/mux.h>
    #include <asm/arch/ddr_defs.h>
    #include <asm/arch/gpio.h>
    #include <asm/emif.h>
    #include "board.h"
    #include <power/pmic.h>
    #include <power/tps65218.h>
    #include <power/tps62362.h>
    #include <miiphy.h>
    #include <cpsw.h>
    #include <linux/usb/gadget.h>
    #include <dwc3-uboot.h>
    #include <dwc3-omap-uboot.h>
    #include <ti-usb-phy-uboot.h>
    #include <asm/types.h>
    
    #define TPS65218_DCDC_VOLT_SEL_1500MV   0x38
    #undef BOARD_FLAG_IS_IDK               
    
    DECLARE_GLOBAL_DATA_PTR;
    
    static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE;
    
    static inline int board_is_idk(void)
    {
        return 0;
    }
    
    /*
     * Read header information from EEPROM into global structure.
     */
    void do_board_detect(void)
    {
    }
    
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
    
    const struct dpll_params dpll_mpu[NUM_CRYSTAL_FREQ][NUM_OPPS] = {
    	{	/* 19.2 MHz */
    		{125, 3, 2, -1, -1, -1, -1},	/* OPP 50 */
    		{-1, -1, -1, -1, -1, -1, -1},	/* OPP RESERVED	*/
    		{125, 3, 1, -1, -1, -1, -1},	/* OPP 100 */
    		{150, 3, 1, -1, -1, -1, -1},	/* OPP 120 */
    		{125, 2, 1, -1, -1, -1, -1},	/* OPP TB */
    		{625, 11, 1, -1, -1, -1, -1}	/* OPP NT */
    	},
    	{	/* 24 MHz */
    		{300, 23, 1, -1, -1, -1, -1},	/* OPP 50 */
    		{-1, -1, -1, -1, -1, -1, -1},	/* OPP RESERVED	*/
    		{600, 23, 1, -1, -1, -1, -1},	/* OPP 100 */
    		{720, 23, 1, -1, -1, -1, -1},	/* OPP 120 */
    		{800, 23, 1, -1, -1, -1, -1},	/* OPP TB */
    		{1000, 23, 1, -1, -1, -1, -1}	/* OPP NT */
    	},
    	{	/* 25 MHz */
    		{300, 24, 1, -1, -1, -1, -1},	/* OPP 50 */
    		{-1, -1, -1, -1, -1, -1, -1},	/* OPP RESERVED	*/
    		{600, 24, 1, -1, -1, -1, -1},	/* OPP 100 */
    		{720, 24, 1, -1, -1, -1, -1},	/* OPP 120 */
    		{800, 24, 1, -1, -1, -1, -1},	/* OPP TB */
    		{1000, 24, 1, -1, -1, -1, -1}	/* OPP NT */
    	},
    	{	/* 26 MHz */
    		{300, 25, 1, -1, -1, -1, -1},	/* OPP 50 */
    		{-1, -1, -1, -1, -1, -1, -1},	/* OPP RESERVED	*/
    		{600, 25, 1, -1, -1, -1, -1},	/* OPP 100 */
    		{720, 25, 1, -1, -1, -1, -1},	/* OPP 120 */
    		{800, 25, 1, -1, -1, -1, -1},	/* OPP TB */
    		{1000, 25, 1, -1, -1, -1, -1}	/* OPP NT */
    	},
    };
    
    const struct dpll_params dpll_core[NUM_CRYSTAL_FREQ] = {
    		{625, 11, -1, -1, 10, 8, 4},	/* 19.2 MHz */
    		{1000, 23, -1, -1, 10, 8, 4},	/* 24 MHz */
    		{1000, 24, -1, -1, 10, 8, 4},	/* 25 MHz */
    		{1000, 25, -1, -1, 10, 8, 4}	/* 26 MHz */
    };
    
    const struct dpll_params dpll_per[NUM_CRYSTAL_FREQ] = {
    		{400, 7, 5, -1, -1, -1, -1},	/* 19.2 MHz */
    		{400, 9, 5, -1, -1, -1, -1},	/* 24 MHz */
    		{384, 9, 5, -1, -1, -1, -1},	/* 25 MHz */
    		{480, 12, 5, -1, -1, -1, -1}	/* 26 MHz */
    };
    
    const struct dpll_params epos_evm_dpll_ddr[NUM_CRYSTAL_FREQ] = {
    		{665, 47, 1, -1, 4, -1, -1}, /*19.2*/
    		{133, 11, 1, -1, 4, -1, -1}, /* 24 MHz */
    		{266, 24, 1, -1, 4, -1, -1}, /* 25 MHz */
    		{133, 12, 1, -1, 4, -1, -1}  /* 26 MHz */
    };
    
    static const struct dpll_params idk_dpll_ddr = {
    	400, 23, 1, -1, 2, -1, -1
    };
    
    static const struct dpll_params leu150_dpll_ddr = {
        400, 24, 1, -1, 2, -1, -1
    };
    
    static const u32 ext_phy_ctrl_const_base_lpddr2[] = {
    	0x00500050,
    	0x00350035,
    	0x00350035,
    	0x00350035,
    	0x00350035,
    	0x00350035,
    	0x00000000,
    	0x00000000,
    	0x00000000,
    	0x00000000,
    	0x00000000,
    	0x00000000,
    	0x00000000,
    	0x00000000,
    	0x00000000,
    	0x00000000,
    	0x00000000,
    	0x00000000,
    	0x40001000,
    	0x08102040
    };
    
    const struct ctrl_ioregs ioregs_ddr3 = {
    	.cm0ioctl		        = DDR3_ADDRCTRL_IOCTRL_VALUE,
    	.cm1ioctl		        = DDR3_ADDRCTRL_WD0_IOCTRL_VALUE,
    	.cm2ioctl		        = DDR3_ADDRCTRL_WD1_IOCTRL_VALUE,
    	.dt0ioctl		        = DDR3_DATA0_IOCTRL_VALUE,
    	.dt1ioctl		        = DDR3_DATA0_IOCTRL_VALUE,
    	.dt2ioctrl		        = DDR3_DATA0_IOCTRL_VALUE,
    	.dt3ioctrl		        = DDR3_DATA0_IOCTRL_VALUE,
    	.emif_sdram_config_ext	= 0xc163,
    };
    
    static const struct emif_regs ddr3_leu150_emif_regs_400Mhz = {
        .sdram_config               = 0x61A11A32,
        .sdram_config2              = 0x00000000,
        .ref_ctrl                   = 0x00000c30,
        .sdram_tim1                 = 0xEAAAD4DB,
        .sdram_tim2                 = 0x262F7FDA,
        .sdram_tim3                 = 0x107F82B8,
        .read_idle_ctrl             = 0x00050000,
        .zq_config                  = 0x50074be4,
        .temp_alert_config          = 0x00000000,
        .emif_ddr_phy_ctlr_1        = 0x00008009,
        .emif_ddr_ext_phy_ctrl_1    = 0x08020080,
        .emif_ddr_ext_phy_ctrl_2    = 0x00000040,
        .emif_ddr_ext_phy_ctrl_3    = 0x0000003e,
        .emif_ddr_ext_phy_ctrl_4    = 0x00000051,
        .emif_ddr_ext_phy_ctrl_5    = 0x00000051,
        .emif_rd_wr_lvl_rmp_win     = 0x00000000,
        .emif_rd_wr_lvl_rmp_ctl     = 0x80000000,
        .emif_rd_wr_lvl_ctl         = 0x00000000,
        .emif_rd_wr_exec_thresh     = 0x00000405,
        .emif_prio_class_serv_map   = 0x00000000,
        .emif_connect_id_serv_1_map = 0x00000000,
        .emif_connect_id_serv_2_map = 0x00000000,
        .emif_cos_config            = 0x00ffffff
    };
    
    static const struct emif_regs ddr3_idk_emif_regs_400Mhz = {
    	.sdram_config			    = 0x61a11b32,
    	.sdram_config2			    = 0x00000000,
    	.ref_ctrl			        = 0x00000c30,
    	.sdram_tim1			        = 0xeaaad4db,
    	.sdram_tim2			        = 0x266b7fda,
    	.sdram_tim3			        = 0x107f8678,
    	.read_idle_ctrl			    = 0x00050000,
    	.zq_config			        = 0x50074be4,
    	.temp_alert_config		    = 0x00000000,
    	.emif_ddr_phy_ctlr_1		= 0x00008009,
    	.emif_ddr_ext_phy_ctrl_1	= 0x08020080,
    	.emif_ddr_ext_phy_ctrl_2	= 0x00000040,
    	.emif_ddr_ext_phy_ctrl_3	= 0x0000003e,
    	.emif_ddr_ext_phy_ctrl_4	= 0x00000051,
    	.emif_ddr_ext_phy_ctrl_5	= 0x00000051,
    	.emif_rd_wr_lvl_rmp_win		= 0x00000000,
    	.emif_rd_wr_lvl_rmp_ctl		= 0x00000000,
    	.emif_rd_wr_lvl_ctl		    = 0x00000000,
    	.emif_rd_wr_exec_thresh		= 0x00000405,
    	.emif_prio_class_serv_map	= 0x00000000,
    	.emif_connect_id_serv_1_map	= 0x00000000,
    	.emif_connect_id_serv_2_map	= 0x00000000,
    	.emif_cos_config		    = 0x00ffffff
    };
    
    void emif_get_ext_phy_ctrl_const_regs(const u32 **regs, u32 *size)
    {    
    }
    
    const struct dpll_params *get_dpll_ddr_params(void)
    {       
    #ifdef BOARD_FLAG_IS_IDK
            return &idk_dpll_ddr;
    #else
            return &leu150_dpll_ddr;
    #endif	
    }
    
    
    /*
     * get_opp_offset:
     * Returns the index for safest OPP of the device to boot.
     * max_off:	Index of the MAX OPP in DEV ATTRIBUTE register.
     * min_off:	Index of the MIN OPP in DEV ATTRIBUTE register.
     * This data is read from dev_attribute register which is e-fused.
     * A'1' in bit indicates OPP disabled and not available, a '0' indicates
     * OPP available. Lowest OPP starts with min_off. So returning the
     * bit with rightmost '0'.
     */
    static int get_opp_offset(int max_off, int min_off)
    {
    	struct ctrl_stat *ctrl = (struct ctrl_stat *)CTRL_BASE;
    	int opp, offset, i;
    	
    	/* Bits 0:11 are defined to be the MPU_MAX_FREQ */
    	opp = readl(&ctrl->dev_attr) & ~0xFFFFF000;
    
    	for (i = max_off; i >= min_off; i--) {
    		offset = opp & (1 << i);
    		if (!offset)
    			return i;
    	}
    
    	return min_off;
    }
    
    const struct dpll_params *get_dpll_mpu_params(void)
    {
    	int opp = get_opp_offset(DEV_ATTR_MAX_OFFSET, DEV_ATTR_MIN_OFFSET);
    	u32 ind = get_sys_clk_index();
    
    	return &dpll_mpu[ind][opp];
    }
    
    const struct dpll_params *get_dpll_core_params(void)
    {
    	int ind = get_sys_clk_index();
    	
    	return &dpll_core[ind];
    }
    
    const struct dpll_params *get_dpll_per_params(void)
    {
    	int ind = get_sys_clk_index();
    	
    	return &dpll_per[ind];
    }
    
    void scale_vcores_generic(u32 m)
    {
    	int mpu_vdd;
    
    	if (i2c_probe(TPS65218_CHIP_PM))
    		return;
    
    	switch (m) {
    	case 1000:
    		mpu_vdd = TPS65218_DCDC_VOLT_SEL_1330MV;
    		break;
    	case 800:
    		mpu_vdd = TPS65218_DCDC_VOLT_SEL_1260MV;
    		break;
    	case 720:
    		mpu_vdd = TPS65218_DCDC_VOLT_SEL_1200MV;
    		break;
    	case 600:
    		mpu_vdd = TPS65218_DCDC_VOLT_SEL_1100MV;
    		break;
    	case 300:
    		mpu_vdd = TPS65218_DCDC_VOLT_SEL_0950MV;
    		break;
    	default:
    		puts("Unknown MPU clock, not scaling\n");
    		return;
    	}
    
    	// Set DCDC1 (CORE) voltage to 1.1V 
    	if (tps65218_voltage_update(TPS65218_DCDC1, TPS65218_DCDC_VOLT_SEL_1100MV)) {
    		printf("%s failure\n", __func__);
    		return;
    	}
    
    	// Set DCDC2 (MPU) voltage 
    	if (tps65218_voltage_update(TPS65218_DCDC2, mpu_vdd)) {
    		printf("%s failure\n", __func__);
    		return;
    	}
    
    	// Set DCDC3 (DDR) voltage 
    	if (tps65218_voltage_update(TPS65218_DCDC3, TPS65218_DCDC_VOLT_SEL_1500MV)){ 
    		printf("%s failure\n", __func__);
    		return;
    	}
    }
    
    void scale_vcores_idk(u32 m)
    {
    	int mpu_vdd;
    
    	if (i2c_probe(TPS62362_I2C_ADDR))
    		return;
    
    	switch (m) {
    	case 1000:
    		mpu_vdd = TPS62362_DCDC_VOLT_SEL_1330MV;
    		break;
    	case 800:
    		mpu_vdd = TPS62362_DCDC_VOLT_SEL_1260MV;
    		break;
    	case 720:
    		mpu_vdd = TPS62362_DCDC_VOLT_SEL_1200MV;
    		break;
    	case 600:
    		mpu_vdd = TPS62362_DCDC_VOLT_SEL_1100MV;
    		break;
    	case 300:
    		mpu_vdd = TPS62362_DCDC_VOLT_SEL_1330MV;
    		break;
    	default:
    		puts("Unknown MPU clock, not scaling\n");
    		return;
    	}
    
    	// Set VDD_MPU voltage 
    	if (tps62362_voltage_update(TPS62362_SET3, mpu_vdd)) {
    		printf("%s failure\n", __func__);
    		return;
    	}
    }
    
    void gpi2c_init(void)
    {
    	// When needed to be invoked prior to BSS initialization 
    	static bool first_time = true;
    
    	if (first_time) {
    		enable_i2c0_pin_mux();
    		i2c_init(CONFIG_SYS_OMAP24_I2C_SPEED, CONFIG_SYS_OMAP24_I2C_SLAVE);
    		first_time = false;
    	}
    }
    
    void scale_vcores(void)
    {
        const struct dpll_params *mpu_params;
        // Ensure I2C is initialized for PMIC configuration 
        gpi2c_init();
        
        // Get the frequency 
        mpu_params = get_dpll_mpu_params();
        
        if (board_is_idk()) {            
            scale_vcores_idk(mpu_params->m);
        } else {
            scale_vcores_generic(mpu_params->m);
        }
    }
    
    void set_uart_mux_conf(void)
    {
    	enable_uart0_pin_mux();
    }
    
    void set_mux_conf_regs(void)
    {
    	enable_board_pin_mux();
    }
    
    static void enable_vtt_regulator(void)
    {
    	u32 temp;
    	
    	/* enable module */
    	writel(GPIO_CTRL_ENABLEMODULE, AM33XX_GPIO5_BASE + OMAP_GPIO_CTRL);
    
    	/* enable output for GPIO5_7 */
    	writel(GPIO_SETDATAOUT(7),
    	       AM33XX_GPIO5_BASE + OMAP_GPIO_SETDATAOUT);
    	temp = readl(AM33XX_GPIO5_BASE + OMAP_GPIO_OE);
    	temp = temp & ~(GPIO_OE_ENABLE(7));
    	writel(temp, AM33XX_GPIO5_BASE + OMAP_GPIO_OE);
    }
    
    enum {
    	RTC_BOARD_EPOS = 1,
    	RTC_BOARD_EVM14,
    	RTC_BOARD_EVM12,
    	RTC_BOARD_GPEVM,
    	RTC_BOARD_SK,
    };
    
    /*
     * In the rtc_only boot path we have the board type info in the rtc scratch pad
     * register hence we bypass the costly i2c reads to eeprom and directly program
     * the board name string
     */
    void rtc_only_update_board_type(u32 btype)
    {
        // TODO do this correctly
    }
    
    u32 rtc_only_get_board_type(void)
    {
        // TODO do this correctly
    	return 0;
    }
    
    void sdram_init(void)
    {
    #ifdef BOARD_FLAG_IS_IDK
            config_ddr(400, &ioregs_ddr3, NULL, NULL, &ddr3_idk_emif_regs_400Mhz, 0);
    #else
            config_ddr(400, &ioregs_ddr3, NULL, NULL, &ddr3_leu150_emif_regs_400Mhz, 0);
    #endif
    }
    #endif
    
    /* setup board specific PMIC */
    int power_init_board(void)
    {
    	struct pmic *p;
    	
    #ifdef BOARD_FLAG_IS_IDK
            power_tps62362_init(I2C_PMIC);
            p = pmic_get("TPS62362");
            if (p && !pmic_probe(p))
                puts("PMIC:  TPS62362\n");
    #else
            power_tps65218_init(I2C_PMIC);
            p = pmic_get("TPS65218_PMIC");
            if (p && !pmic_probe(p))
                puts("PMIC:  TPS65218\n");
    #endif
    
    	return 0;
    }
    
    int board_init(void)
    {
    	struct l3f_cfg_bwlimiter *bwlimiter = (struct l3f_cfg_bwlimiter *)L3F_CFG_BWLIMITER;
    	u32 mreqprio_0, mreqprio_1, modena_init0_bw_fractional,
    	    modena_init0_bw_integer, modena_init0_watermark_0;
    
    	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
    	gpmc_init();
    
    	/* Clear all important bits for DSS errata that may need to be tweaked*/
    	mreqprio_0 = readl(&cdev->mreqprio_0) & MREQPRIO_0_SAB_INIT1_MASK & MREQPRIO_0_SAB_INIT0_MASK;
    	mreqprio_1 = readl(&cdev->mreqprio_1) & MREQPRIO_1_DSS_MASK;
    
    	modena_init0_bw_fractional = readl(&bwlimiter->modena_init0_bw_fractional) & BW_LIMITER_BW_FRAC_MASK;
    	modena_init0_bw_integer = readl(&bwlimiter->modena_init0_bw_integer) & BW_LIMITER_BW_INT_MASK;
    	modena_init0_watermark_0 = readl(&bwlimiter->modena_init0_watermark_0) & BW_LIMITER_BW_WATERMARK_MASK;
    
    	/* Setting MReq Priority of the DSS*/
    	mreqprio_0 |= 0x77;
    
    	/*
    	 * Set L3 Fast Configuration Register
    	 * Limiting bandwith for ARM core to 700 MBPS
    	 */
    	modena_init0_bw_fractional |= 0x10;
    	modena_init0_bw_integer |= 0x3;
    
    	writel(mreqprio_0, &cdev->mreqprio_0);
    	writel(mreqprio_1, &cdev->mreqprio_1);
    
    	writel(modena_init0_bw_fractional, &bwlimiter->modena_init0_bw_fractional);
    	writel(modena_init0_bw_integer, &bwlimiter->modena_init0_bw_integer);
    	writel(modena_init0_watermark_0, &bwlimiter->modena_init0_watermark_0);
    
    	return 0;
    }
    
    #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
    void set_board_info_env()
    {
        setenv("board_name", "TAU-Board");
    }
    #endif;
    
    #ifdef CONFIG_BOARD_LATE_INIT
    int board_late_init(void)
    {
    #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
    	set_board_info_env(); 
    
    	/*
    	 * Default FIT boot on HS devices. Non FIT images are not allowed
    	 * on HS devices.
    	 */
    	if (get_device_type() == HS_DEVICE)
    		setenv("boot_fit", "1");
    #endif
    	return 0;
    }
    #endif
    
    #ifdef CONFIG_USB_DWC3
    static struct dwc3_device usb_otg_ss1 = {
    	.maximum_speed = USB_SPEED_HIGH,
    	.base = USB_OTG_SS1_BASE,
    	.tx_fifo_resize = false,
    	.index = 0,
    };
    
    static struct dwc3_omap_device usb_otg_ss1_glue = {
    	.base = (void *)USB_OTG_SS1_GLUE_BASE,
    	.utmi_mode = DWC3_OMAP_UTMI_MODE_SW,
    	.index = 0,
    };
    
    static struct ti_usb_phy_device usb_phy1_device = {
    	.usb2_phy_power = (void *)USB2_PHY1_POWER,
    	.index = 0,
    };
    
    static struct dwc3_device usb_otg_ss2 = {
    	.maximum_speed = USB_SPEED_HIGH,
    	.base = USB_OTG_SS2_BASE,
    	.tx_fifo_resize = false,
    	.index = 1,
    };
    
    static struct dwc3_omap_device usb_otg_ss2_glue = {
    	.base = (void *)USB_OTG_SS2_GLUE_BASE,
    	.utmi_mode = DWC3_OMAP_UTMI_MODE_SW,
    	.index = 1,
    };
    
    static struct ti_usb_phy_device usb_phy2_device = {
    	.usb2_phy_power = (void *)USB2_PHY2_POWER,
    	.index = 1,
    };
    
    int usb_gadget_handle_interrupts(int index)
    {
    	u32 status;
    
    	status = dwc3_omap_uboot_interrupt_status(index);
    	if (status)
    		dwc3_uboot_handle_interrupt(index);
    
    	return 0;
    }
    #endif /* CONFIG_USB_DWC3 */
    
    #if defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_XHCI_OMAP)
    int board_usb_init(int index, enum usb_init_type init)
    {
    	enable_usb_clocks(index);
    #ifdef CONFIG_USB_DWC3
    	switch (index) {
    	case 0:
    		if (init == USB_INIT_DEVICE) {
    			usb_otg_ss1.dr_mode = USB_DR_MODE_PERIPHERAL;
    			usb_otg_ss1_glue.vbus_id_status = OMAP_DWC3_VBUS_VALID;
    			dwc3_omap_uboot_init(&usb_otg_ss1_glue);
    			ti_usb_phy_uboot_init(&usb_phy1_device);
    			dwc3_uboot_init(&usb_otg_ss1);
    		}
    		break;
    	case 1:
    		if (init == USB_INIT_DEVICE) {
    			usb_otg_ss2.dr_mode = USB_DR_MODE_PERIPHERAL;
    			usb_otg_ss2_glue.vbus_id_status = OMAP_DWC3_VBUS_VALID;
    			ti_usb_phy_uboot_init(&usb_phy2_device);
    			dwc3_omap_uboot_init(&usb_otg_ss2_glue);
    			dwc3_uboot_init(&usb_otg_ss2);
    		}
    		break;
    	default:
    		printf("Invalid Controller Index\n");
    	}
    #endif
    
    	return 0;
    }
    
    int board_usb_cleanup(int index, enum usb_init_type init)
    {
    #ifdef CONFIG_USB_DWC3
    	switch (index) {
    	case 0:
    	case 1:
    		if (init == USB_INIT_DEVICE) {
    			ti_usb_phy_uboot_exit(index);
    			dwc3_uboot_exit(index);
    			dwc3_omap_uboot_exit(index);
    		}
    		break;
    	default:
    		printf("Invalid Controller Index\n");
    	}
    #endif
    	disable_usb_clocks(index);
    
    	return 0;
    }
    #endif /* defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_XHCI_OMAP) */
    
    #ifndef CONFIG_DM_ETH
    #if (defined(CONFIG_DRIVER_TI_CPSW) && !defined(CONFIG_SPL_BUILD)) || \
    	(defined(CONFIG_SPL_ETH_SUPPORT) && defined(CONFIG_SPL_BUILD))
    static void cpsw_control(int enabled)
    {
    	/* Additional controls can be added here */
    	return;
    }
    
    static struct cpsw_slave_data cpsw_slaves[] = {
    	{
    		.slave_reg_ofs	= 0x208,
    		.sliver_reg_ofs	= 0xd80,
    		.phy_addr	= 16,
    	},
    	{
    		.slave_reg_ofs	= 0x308,
    		.sliver_reg_ofs	= 0xdc0,
    		.phy_addr	= 1,
    	},
    };
    
    static struct cpsw_platform_data cpsw_data = {
    	.mdio_base		    = CPSW_MDIO_BASE,
    	.cpsw_base		    = CPSW_BASE,
    	.mdio_div		    = 0xff,
    	.channels		    = 8,
    	.cpdma_reg_ofs		= 0x800,
    	.slaves			    = 1,
    	.slave_data		    = cpsw_slaves,
    	.ale_reg_ofs		= 0xd00,
    	.ale_entries		= 1024,
    	.host_port_reg_ofs	= 0x108,
    	.hw_stats_reg_ofs	= 0x900,
    	.bd_ram_ofs		    = 0x2000,
    	.mac_control		= (1 << 5),
    	.control		    = cpsw_control,
    	.host_port_num		= 0,
    	.version		    = CPSW_CTRL_VERSION_2,
    };
    #endif
    
    
    /*
     * This function will:
     * Read the eFuse for MAC addresses, and set ethaddr/eth1addr/usbnet_devaddr
     * in the environment
     * Perform fixups to the PHY present on certain boards.  We only need this
     * function in:
     * - SPL with either CPSW or USB ethernet support
     * - Full U-Boot, with either CPSW or USB ethernet
     * Build in only these cases to avoid warnings about unused variables
     * when we build an SPL that has neither option but full U-Boot will.
     */
    #if ((defined(CONFIG_SPL_ETH_SUPPORT) || \
    	defined(CONFIG_SPL_USBETH_SUPPORT)) && \
    	defined(CONFIG_SPL_BUILD)) || \
    	((defined(CONFIG_DRIVER_TI_CPSW) || \
    	  defined(CONFIG_USB_ETHER)) && !defined(CONFIG_SPL_BUILD))
    int board_eth_init(bd_t *bis)
    {
    	int rv;
    	uint8_t mac_addr[6];
    	uint32_t mac_hi, mac_lo;
    	
    	/* try reading mac address from efuse */
    	mac_lo = readl(&cdev->macid0l);
    	mac_hi = readl(&cdev->macid0h);
    	mac_addr[0] = mac_hi & 0xFF;
    	mac_addr[1] = (mac_hi & 0xFF00) >> 8;
    	mac_addr[2] = (mac_hi & 0xFF0000) >> 16;
    	mac_addr[3] = (mac_hi & 0xFF000000) >> 24;
    	mac_addr[4] = mac_lo & 0xFF;
    	mac_addr[5] = (mac_lo & 0xFF00) >> 8;
    
    #if (defined(CONFIG_DRIVER_TI_CPSW) && !defined(CONFIG_SPL_BUILD)) || \
    	(defined(CONFIG_SPL_ETH_SUPPORT) && defined(CONFIG_SPL_BUILD))
    	if (!getenv("ethaddr")) {
    		puts("<ethaddr> not set. Validating first E-fuse MAC\n");
    		if (is_valid_ethaddr(mac_addr))
    			eth_setenv_enetaddr("ethaddr", mac_addr);
    	}
    
    #ifndef CONFIG_SPL_BUILD
    	mac_lo = readl(&cdev->macid1l);
    	mac_hi = readl(&cdev->macid1h);
    	mac_addr[0] = mac_hi & 0xFF;
    	mac_addr[1] = (mac_hi & 0xFF00) >> 8;
    	mac_addr[2] = (mac_hi & 0xFF0000) >> 16;
    	mac_addr[3] = (mac_hi & 0xFF000000) >> 24;
    	mac_addr[4] = mac_lo & 0xFF;
    	mac_addr[5] = (mac_lo & 0xFF00) >> 8;
    
    	if (!getenv("eth1addr")) {
    		if (is_valid_ethaddr(mac_addr))
    			eth_setenv_enetaddr("eth1addr", mac_addr);
    	}
    #endif
    
    	if (board_is_idk()) {
            writel(RGMII_MODE_ENABLE, &cdev->miisel);
            cpsw_slaves[0].phy_if = PHY_INTERFACE_MODE_RGMII;
            cpsw_slaves[0].phy_addr = 0;
        } else {
            writel(RGMII_MODE_ENABLE, &cdev->miisel);
            cpsw_slaves[0].phy_if = PHY_INTERFACE_MODE_RGMII;
            cpsw_slaves[0].phy_addr = 0;
        }
    
    	rv = cpsw_register(&cpsw_data);
    	if (rv < 0) {
    		printf("Error %d registering CPSW switch\n", rv);
    		return rv;
    	}
    #endif
    #if defined(CONFIG_USB_ETHER) && \
    	(!defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_USBETH_SUPPORT))
    	if (is_valid_ethaddr(mac_addr))
    		eth_setenv_enetaddr("usbnet_devaddr", mac_addr);
    
    	rv = usb_eth_initialize(bis);
    	if (rv < 0)
    		printf("Error %d registering USB_ETHER\n", rv);
    #endif
    
    	return rv;
    }
    #endif
    #endif
    
    #if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
    int ft_board_setup(void *blob, bd_t *bd)
    {
    	ft_cpu_setup(blob, bd);
    
    	return 0;
    }
    #endif
    
    #ifdef CONFIG_SPL_LOAD_FIT
    int board_fit_config_name_match(const char *name)
    {    
        if (board_is_idk() && !strcmp(name, "am437x-idk-evm"))        
            return 0;
        else
            return 0;
    }
    #endif
    
    #ifdef CONFIG_TI_SECURE_DEVICE
    void board_fit_image_post_process(void **p_image, size_t *p_size)
    {
    	secure_boot_verify_image(p_image, p_size);
    }
    
    void board_tee_image_process(ulong tee_image, size_t tee_size)
    {
    	secure_tee_install((u32)tee_image);
    }
    
    U_BOOT_FIT_LOADABLE_HANDLER(IH_TYPE_TEE, board_tee_image_process);
    #endif
    

    5684.board.h
    #include <common.h>
    #include <asm/arch/sys_proto.h>
    #include <asm/arch/mux.h>
    #include "board.h"
    
    static struct module_pin_mux rmii1_pin_mux[] = {
    	{OFFSET(mii1_txen), MODE(1)},			/* RMII1_TXEN */
    	{OFFSET(mii1_txd1), MODE(1)},			/* RMII1_TD1 */
    	{OFFSET(mii1_txd0), MODE(1)},			/* RMII1_TD0 */
    	{OFFSET(mii1_rxd1), MODE(1) | RXACTIVE},	/* RMII1_RD1 */
    	{OFFSET(mii1_rxd0), MODE(1) | RXACTIVE},	/* RMII1_RD0 */
    	{OFFSET(mii1_rxdv), MODE(1) | RXACTIVE},	/* RMII1_RXDV */
    	{OFFSET(mii1_crs), MODE(1) | RXACTIVE},		/* RMII1_CRS_DV */
    	{OFFSET(mii1_rxerr), MODE(1) | RXACTIVE},	/* RMII1_RXERR */
    	{OFFSET(rmii1_refclk), MODE(0) | RXACTIVE},	/* RMII1_refclk */
    	{-1},
    };
    
    static struct module_pin_mux rgmii1_pin_mux[] = {
    	{OFFSET(mii1_txen), MODE(2)},			/* RGMII1_TCTL */
    	{OFFSET(mii1_rxdv), MODE(2) | RXACTIVE},	/* RGMII1_RCTL */
    	{OFFSET(mii1_txd3), MODE(2)},			/* RGMII1_TD3 */
    	{OFFSET(mii1_txd2), MODE(2)},			/* RGMII1_TD2 */
    	{OFFSET(mii1_txd1), MODE(2)},			/* RGMII1_TD1 */
    	{OFFSET(mii1_txd0), MODE(2)},			/* RGMII1_TD0 */
    	{OFFSET(mii1_txclk), MODE(2)},			/* RGMII1_TCLK */
    	{OFFSET(mii1_rxclk), MODE(2) | RXACTIVE},	/* RGMII1_RCLK */
    	{OFFSET(mii1_rxd3), MODE(2) | RXACTIVE},	/* RGMII1_RD3 */
    	{OFFSET(mii1_rxd2), MODE(2) | RXACTIVE},	/* RGMII1_RD2 */
    	{OFFSET(mii1_rxd1), MODE(2) | RXACTIVE},	/* RGMII1_RD1 */
    	{OFFSET(mii1_rxd0), MODE(2) | RXACTIVE},	/* RGMII1_RD0 */
    	{-1},
    };
    
    static struct module_pin_mux mdio_pin_mux[] = {
    	{OFFSET(mdio_data), MODE(0) | RXACTIVE | PULLUP_EN},/* MDIO_DATA */
    	{OFFSET(mdio_clk), MODE(0) | PULLUP_EN},	/* MDIO_CLK */
    	{-1},
    };
    
    static struct module_pin_mux uart0_pin_mux[] = {
    	{OFFSET(uart0_rxd), (MODE(0) | PULLUP_EN | RXACTIVE | SLEWCTRL)},
    	{OFFSET(uart0_txd), (MODE(0) | PULLUDDIS | PULLUP_EN | SLEWCTRL)},
    	{-1},
    };
    
    static struct module_pin_mux mmc0_pin_mux[] = {
    	{OFFSET(mmc0_clk), (MODE(0) | PULLUDDIS | RXACTIVE)},  /* MMC0_CLK */
    	{OFFSET(mmc0_cmd), (MODE(0) | PULLUP_EN | RXACTIVE)},  /* MMC0_CMD */
    	{OFFSET(mmc0_dat0), (MODE(0) | PULLUP_EN | RXACTIVE)}, /* MMC0_DAT0 */
    	{OFFSET(mmc0_dat1), (MODE(0) | PULLUP_EN | RXACTIVE)}, /* MMC0_DAT1 */
    	{OFFSET(mmc0_dat2), (MODE(0) | PULLUP_EN | RXACTIVE)}, /* MMC0_DAT2 */
    	{OFFSET(mmc0_dat3), (MODE(0) | PULLUP_EN | RXACTIVE)}, /* MMC0_DAT3 */
    	{-1},
    };
    
    static struct module_pin_mux i2c0_pin_mux[] = {
    	{OFFSET(i2c0_sda), (MODE(0) | PULLUP_EN | RXACTIVE | SLEWCTRL)},
    	{OFFSET(i2c0_scl), (MODE(0) | PULLUP_EN | RXACTIVE | SLEWCTRL)},
    	{-1},
    };
    
    static struct module_pin_mux gpio5_7_pin_mux[] = {
    	{OFFSET(spi0_cs0), (MODE(7) | PULLUP_EN)},	/* GPIO5_7 */
    	{-1},
    };
    
    #ifdef CONFIG_NAND
    static struct module_pin_mux nand_pin_mux[] = {
    	{OFFSET(gpmc_ad0),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD0 */
    	{OFFSET(gpmc_ad1),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD1 */
    	{OFFSET(gpmc_ad2),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD2 */
    	{OFFSET(gpmc_ad3),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD3 */
    	{OFFSET(gpmc_ad4),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD4 */
    	{OFFSET(gpmc_ad5),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD5 */
    	{OFFSET(gpmc_ad6),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD6 */
    	{OFFSET(gpmc_ad7),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD7 */
    #ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT
    	{OFFSET(gpmc_ad8),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD8  */
    	{OFFSET(gpmc_ad9),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD9  */
    	{OFFSET(gpmc_ad10),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD10 */
    	{OFFSET(gpmc_ad11),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD11 */
    	{OFFSET(gpmc_ad12),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD12 */
    	{OFFSET(gpmc_ad13),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD13 */
    	{OFFSET(gpmc_ad14),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD14 */
    	{OFFSET(gpmc_ad15),	(MODE(0) | PULLUDDIS | RXACTIVE)}, /* AD15 */
    #endif
    	{OFFSET(gpmc_wait0),	(MODE(0) | RXACTIVE | PULLUP_EN)}, /* Wait */
    	{OFFSET(gpmc_wpn),	(MODE(7) | PULLUP_EN)},	/* Write Protect */
    	{OFFSET(gpmc_csn0),	(MODE(0) | PULLUP_EN)},	/* Chip-Select */
    	{OFFSET(gpmc_wen),	(MODE(0) | PULLDOWN_EN)}, /* Write Enable */
    	{OFFSET(gpmc_oen_ren),	(MODE(0) | PULLDOWN_EN)}, /* Read Enable */
    	{OFFSET(gpmc_advn_ale),	(MODE(0) | PULLDOWN_EN)}, /* Addr Latch Enable*/
    	{OFFSET(gpmc_be0n_cle),	(MODE(0) | PULLDOWN_EN)}, /* Byte Enable */
    	{-1},
    };
    #endif
    
    static __maybe_unused struct module_pin_mux qspi_pin_mux[] = {
    	{OFFSET(gpmc_csn0), (MODE(3) | PULLUP_EN | RXACTIVE)}, /* QSPI_CS0 */
    	{OFFSET(gpmc_csn3), (MODE(2) | PULLUP_EN | RXACTIVE)}, /* QSPI_CLK */
    	{OFFSET(gpmc_advn_ale), (MODE(3) | PULLUP_EN | RXACTIVE)}, /* QSPI_D0 */
    	{OFFSET(gpmc_oen_ren), (MODE(3) | PULLUP_EN | RXACTIVE)}, /* QSPI_D1 */
    	{OFFSET(gpmc_wen), (MODE(3) | PULLUP_EN | RXACTIVE)}, /* QSPI_D2 */
    	{OFFSET(gpmc_be0n_cle), (MODE(3) | PULLUP_EN | RXACTIVE)}, /* QSPI_D3 */
    	{-1},
    };
    
    void enable_uart0_pin_mux(void)
    {
    	configure_module_pin_mux(uart0_pin_mux);
    }
    
    void enable_board_pin_mux(void)
    {
    	configure_module_pin_mux(mmc0_pin_mux);
    	configure_module_pin_mux(i2c0_pin_mux);
    	configure_module_pin_mux(mdio_pin_mux);
    }
    
    void enable_i2c0_pin_mux(void)
    {
    	configure_module_pin_mux(i2c0_pin_mux);
    }
    

    AM43xx_DDR_register_AS4C64M16D3A-12BIN.xls

  • Please use this EMIF tool instead of the spread sheet that you attached here.

    www.ti.com/lit/an/sprac70/sprac70.pdf

    Let us know if you find the same issue with this.

    Regards, Siva
  • Hey Siva

    Thank you for you answer. Meanwhile I used this sheet also with no effect.

    You will find the sheet as attachment.

    Regards, Thomas

    6281.SPRAC70_AM437x_EMIF_Configuration_Tool_V20.xlsx

  • Thomas

    Can you share your schematics?

    Regards, Siva
  • Thomas,

    One issue is that the spreadsheet is specifying to use invert_clock=1, which has an impact on the programming of EXT_PHY_CTRL1 and EXT_PHY_CTRL1_SHADOW.

    Take a look in u-boot at the file arch/arm/mach-omap2/am33xx/ddr.c.  In particular look at the ext_phy_settings_hwlvl() function.  You'll notice the values there don't match up with the "Registers" sheet.  I recommend fixing it as follows:

    diff --git a/arch/arm/mach-omap2/am33xx/ddr.c b/arch/arm/mach-omap2/am33xx/ddr.c
    index 690487e..12c10b4 100644
    --- a/arch/arm/mach-omap2/am33xx/ddr.c
    +++ b/arch/arm/mach-omap2/am33xx/ddr.c
    @@ -248,8 +248,15 @@ static void ext_phy_settings_hwlvl(const struct emif_regs *regs, int nr)
    * Enable hardware leveling on the EMIF. For details about these
    * magic values please see the EMIF registers section of the TRM.
    */
    - writel(0x08020080, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_1);
    - writel(0x08020080, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_1_shdw);
    + if (regs->emif_ddr_phy_ctlr_1 & 0x00040000) {
    + /* PHY_INVERT_CLKOUT = 1 */
    + writel(0x00040100, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_1);
    + writel(0x00040100, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_1_shdw);
    + } else {
    + /* PHY_INVERT_CLKOUT = 0 */
    + writel(0x08020080, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_1);
    + writel(0x08020080, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_1_shdw);
    + }
    writel(0x00000000, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_22);
    writel(0x00000000, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_22_shdw);
    writel(0x00600020, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_23);

    Let us know if that does the trick for you.

    Best regards,
    Brad

  • Hey Brad & Siva

    This resolves my issue, thank you so much! Is there a need to contribute this patch to the U-boot repository?

    @Siva The DDR3 schematic section identical with the IDK section.

    Thank you for your support!

    Best regards,
    Thomas
  • Hi Thomas,

    I have now filed this issue as LCPD-12244.  Our Linux/u-boot team will get it integrated.  I'm glad to hear things are working!

    Best regards,
    Brad