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.

AM5718: IO Calibration suspect of causing Improper Boot-up on First Boot-up

Part Number: AM5718

TI Friends and Family,

Our customer is experiencing about a 15% rate of AM5718 devices that do not boot-up on first boot-up.  They are failing the TI recommended I/O calibration.

The team is not having any success resolving this issue quite yet so I hoping maybe to get further assistance.

We believe they have tried an automatic reboot but this does not always work so I don't think this is a smoking gun.  One first thought is that there is a problem in the schematic or in the layout with the impedance matching which is why the AM5718 is getting mad on boot-up.  I can forward both separately.

In an attempt to help get to a root cause, I have pasted our initial comments below:

----

First off, from what I digest on the TI E2E forums, rather than a simple reboot, it looks like the suggested steps below are what was recommended (and still would be) by TI for a proper IO recalibration sequence: 

  • IODELAY recalibration sequence:
  • - Complete AVS voltage change on VDD_CORE_L
  • - Unlock IODLAY config registers.
  • - Perform IO delay calibration with predefined values.
  • - Isolate all the IOs
  • - Update the delay mechanism for each IO with new calibrated values.
  • - Configure PAD configuration registers
  • - De-isolate all the IOs.

- Relock IODELAY config registers.

We have asked if this is being followed?

 Secondly, if not using AVS (Adaptive Voltage Scaling) then you can actually create the iodelay files by using the TI pinmux tool for the processor.  You can get the tool from the below link:  http://www.ti.com/tool/PINMUXTOOL

 Lastly, if you are using AVS then you need to recalibrate the iodelay.  Please refer to the TRM Technical Reference Manual, as it has all the details to help do this.

 ***One other thing to keep in mind is that when using AVS you have to program a register that changes the IOdelay for each peripheral.  Please again review the latest TRM and take  a look at section 18.4.6.1.8 IO Delay Recalibration. This should not affect what you are seeing but in the final product you need to do this to make sure you meet the timing for each IO.***

-----

As always I appreciate anyone's support.  Any additional comments or guidance appreciated.

TY,

CY

  • Team,

    Additional info to consider:

    Attaching code incl the proposed solution. The changes in board.c are near the 440 line to 460 area. The Change in autoboot.c is around the 226-235 lines. Both those references are in the proposed section. Concern is - in the proposed - the calls to do_set_mux32 and do_set_iodelay (others) are executed when the I/O cal fails in the proposed and not in the current. Customer wrote a version of board.c which allowed for the reboot but followed the current board.c (didn’t set the registers) and reported that this experimental version of board.c failed. My conclusion is that just rebooting does not solve the problem. It is persistent and not a transient of power, etc.

    Also, to answer the question about whether the recalibration sequence is being followed ...in the original code: yes, in the proposed not when the calibrate fails. They included a re-write of registers then rebooted.

    (proposed) autoboot.c
    /*
     * (C) Copyright 2000
     * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
     *
     * SPDX-License-Identifier:	GPL-2.0+
     */
    
    #include <common.h>
    #include <autoboot.h>
    #include <bootretry.h>
    #include <cli.h>
    #include <console.h>
    #include <fdtdec.h>
    #include <menu.h>
    #include <post.h>
    #include <u-boot/sha256.h>
    
    DECLARE_GLOBAL_DATA_PTR;
    
    #define MAX_DELAY_STOP_STR 32
    
    /* Reboot reason - I/O calibration failed */
    #define OCMC_RAM1_REBOOT_REASON_ADDR    0x4035FF00
    #define REBOOT_BY_IO_CAL_ERROR          0x34562301
    
    #ifndef DEBUG_BOOTKEYS
    #define DEBUG_BOOTKEYS 0
    #endif
    #define debug_bootkeys(fmt, args...)		\
    	debug_cond(DEBUG_BOOTKEYS, fmt, ##args)
    
    /* Stored value of bootdelay, used by autoboot_command() */
    static int stored_bootdelay;
    
    #if defined(CONFIG_AUTOBOOT_KEYED)
    #if defined(CONFIG_AUTOBOOT_STOP_STR_SHA256)
    
    /*
     * Use a "constant-length" time compare function for this
     * hash compare:
     *
     * https://crackstation.net/hashing-security.htm
     */
    static int slow_equals(u8 *a, u8 *b, int len)
    {
    	int diff = 0;
    	int i;
    
    	for (i = 0; i < len; i++)
    		diff |= a[i] ^ b[i];
    
    	return diff == 0;
    }
    
    static int passwd_abort(uint64_t etime)
    {
    	const char *sha_env_str = getenv("bootstopkeysha256");
    	u8 sha_env[SHA256_SUM_LEN];
    	u8 sha[SHA256_SUM_LEN];
    	char presskey[MAX_DELAY_STOP_STR];
    	const char *algo_name = "sha256";
    	u_int presskey_len = 0;
    	int abort = 0;
    	int size;
    	int ret;
    
    	if (sha_env_str == NULL)
    		sha_env_str = CONFIG_AUTOBOOT_STOP_STR_SHA256;
    
    	/*
    	 * Generate the binary value from the environment hash value
    	 * so that we can compare this value with the computed hash
    	 * from the user input
    	 */
    	ret = hash_parse_string(algo_name, sha_env_str, sha_env);
    	if (ret) {
    		printf("Hash %s not supported!\n", algo_name);
    		return 0;
    	}
    
    	/*
    	 * We don't know how long the stop-string is, so we need to
    	 * generate the sha256 hash upon each input character and
    	 * compare the value with the one saved in the environment
    	 */
    	do {
    		if (tstc()) {
    			/* Check for input string overflow */
    			if (presskey_len >= MAX_DELAY_STOP_STR)
    				return 0;
    
    			presskey[presskey_len++] = getc();
    
    			/* Calculate sha256 upon each new char */
    			hash_block(algo_name, (const void *)presskey,
    				   presskey_len, sha, &size);
    
    			/* And check if sha matches saved value in env */
    			if (slow_equals(sha, sha_env, SHA256_SUM_LEN))
    				abort = 1;
    		}
    	} while (!abort && get_ticks() <= etime);
    
    	return abort;
    }
    #else
    static int passwd_abort(uint64_t etime)
    {
    	int abort = 0;
    	struct {
    		char *str;
    		u_int len;
    		int retry;
    	}
    	delaykey[] = {
    		{ .str = getenv("bootdelaykey"),  .retry = 1 },
    		{ .str = getenv("bootstopkey"),   .retry = 0 },
    	};
    
    	char presskey[MAX_DELAY_STOP_STR];
    	u_int presskey_len = 0;
    	u_int presskey_max = 0;
    	u_int i;
    
    #  ifdef CONFIG_AUTOBOOT_DELAY_STR
    	if (delaykey[0].str == NULL)
    		delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
    #  endif
    #  ifdef CONFIG_AUTOBOOT_STOP_STR
    	if (delaykey[1].str == NULL)
    		delaykey[1].str = CONFIG_AUTOBOOT_STOP_STR;
    #  endif
    
    	for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) {
    		delaykey[i].len = delaykey[i].str == NULL ?
    				    0 : strlen(delaykey[i].str);
    		delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
    				    MAX_DELAY_STOP_STR : delaykey[i].len;
    
    		presskey_max = presskey_max > delaykey[i].len ?
    				    presskey_max : delaykey[i].len;
    
    		debug_bootkeys("%s key:<%s>\n",
    			       delaykey[i].retry ? "delay" : "stop",
    			       delaykey[i].str ? delaykey[i].str : "NULL");
    	}
    
    	/* In order to keep up with incoming data, check timeout only
    	 * when catch up.
    	 */
    	do {
    		if (tstc()) {
    			if (presskey_len < presskey_max) {
    				presskey[presskey_len++] = getc();
    			} else {
    				for (i = 0; i < presskey_max - 1; i++)
    					presskey[i] = presskey[i + 1];
    
    				presskey[i] = getc();
    			}
    		}
    
    		for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i++) {
    			if (delaykey[i].len > 0 &&
    			    presskey_len >= delaykey[i].len &&
    				memcmp(presskey + presskey_len -
    					delaykey[i].len, delaykey[i].str,
    					delaykey[i].len) == 0) {
    					debug_bootkeys("got %skey\n",
    						delaykey[i].retry ? "delay" :
    						"stop");
    
    				/* don't retry auto boot */
    				if (!delaykey[i].retry)
    					bootretry_dont_retry();
    				abort = 1;
    			}
    		}
    	} while (!abort && get_ticks() <= etime);
    
    	return abort;
    }
    #endif
    
    /***************************************************************************
     * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
     * returns: 0 -  no key string, allow autoboot 1 - got key string, abort
     */
    static int __abortboot(int bootdelay)
    {
    	int abort;
    	uint64_t etime = endtick(bootdelay);
    
    #  ifdef CONFIG_AUTOBOOT_PROMPT
    	/*
    	 * CONFIG_AUTOBOOT_PROMPT includes the %d for all boards.
    	 * To print the bootdelay value upon bootup.
    	 */
    	printf(CONFIG_AUTOBOOT_PROMPT, bootdelay);
    #  endif
    
    	abort = passwd_abort(etime);
    	if (!abort)
    		debug_bootkeys("key timeout\n");
    
    	return abort;
    }
    
    # else	/* !defined(CONFIG_AUTOBOOT_KEYED) */
    
    #ifdef CONFIG_MENUKEY
    static int menukey;
    #endif
    
    static int __abortboot(int bootdelay)
    {
    	int abort = 0;
    	unsigned long ts;
    
    #ifdef CONFIG_MENUPROMPT
    	printf(CONFIG_MENUPROMPT);
    #else
    	printf("Hit any key to stop autoboot: %2d ", bootdelay);
    #endif
    
    	/* MiiS@20200227 DarkHou add for I/O calibration failed issue */
    	int *reboot_reason = (int *) OCMC_RAM1_REBOOT_REASON_ADDR;
    		
            /* MiiS@20200227 When I/O calibration failed, reboot device again */
    	if (*reboot_reason == REBOOT_BY_IO_CAL_ERROR) {
    		do_reset(NULL, 0, 0, NULL);
    	}
    		
    	/*
    	 * Check if key already pressed
    	 */
    	if (tstc()) {	/* we got a key press	*/
    		(void) getc();  /* consume input	*/
    		puts("\b\b\b 0");
    		abort = 1;	/* don't auto boot	*/
    	}
    
    	while ((bootdelay > 0) && (!abort)) {
    		--bootdelay;
    		/* delay 1000 ms */
    		ts = get_timer(0);
    		do {
    			if (tstc()) {	/* we got a key press	*/
    				abort  = 1;	/* don't auto boot	*/
    				bootdelay = 0;	/* no more delay	*/
    # ifdef CONFIG_MENUKEY
    				menukey = getc();
    # else
    				(void) getc();  /* consume input	*/
    # endif
    				break;
    			}
    			udelay(10000);
    		} while (!abort && get_timer(ts) < 1000);
    
    		printf("\b\b\b%2d ", bootdelay);
    	}
    
    	putc('\n');
    
    	return abort;
    }
    # endif	/* CONFIG_AUTOBOOT_KEYED */
    
    static int abortboot(int bootdelay)
    {
    	int abort = 0;
    
    	if (bootdelay >= 0)
    		abort = __abortboot(bootdelay);
    
    #ifdef CONFIG_SILENT_CONSOLE
    	if (abort)
    		gd->flags &= ~GD_FLG_SILENT;
    #endif
    
    	return abort;
    }
    
    static void process_fdt_options(const void *blob)
    {
    #if defined(CONFIG_OF_CONTROL) && defined(CONFIG_SYS_TEXT_BASE)
    	ulong addr;
    
    	/* Add an env variable to point to a kernel payload, if available */
    	addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0);
    	if (addr)
    		setenv_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
    
    	/* Add an env variable to point to a root disk, if available */
    	addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0);
    	if (addr)
    		setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
    #endif /* CONFIG_OF_CONTROL && CONFIG_SYS_TEXT_BASE */
    }
    
    const char *bootdelay_process(void)
    {
    	char *s;
    	int bootdelay;
    #ifdef CONFIG_BOOTCOUNT_LIMIT
    	unsigned long bootcount = 0;
    	unsigned long bootlimit = 0;
    #endif /* CONFIG_BOOTCOUNT_LIMIT */
    
    #ifdef CONFIG_BOOTCOUNT_LIMIT
    	bootcount = bootcount_load();
    	bootcount++;
    	bootcount_store(bootcount);
    	setenv_ulong("bootcount", bootcount);
    	bootlimit = getenv_ulong("bootlimit", 10, 0);
    #endif /* CONFIG_BOOTCOUNT_LIMIT */
    
    	s = getenv("bootdelay");
    	bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
    
    #ifdef CONFIG_OF_CONTROL
    	bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay",
    			bootdelay);
    #endif
    
    	debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);
    
    #if defined(CONFIG_MENU_SHOW)
    	bootdelay = menu_show(bootdelay);
    #endif
    	bootretry_init_cmd_timeout();
    
    #ifdef CONFIG_POST
    	if (gd->flags & GD_FLG_POSTFAIL) {
    		s = getenv("failbootcmd");
    	} else
    #endif /* CONFIG_POST */
    #ifdef CONFIG_BOOTCOUNT_LIMIT
    	if (bootlimit && (bootcount > bootlimit)) {
    		printf("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
    		       (unsigned)bootlimit);
    		s = getenv("altbootcmd");
    	} else
    #endif /* CONFIG_BOOTCOUNT_LIMIT */
    		s = getenv("bootcmd");
    
    	process_fdt_options(gd->fdt_blob);
    	stored_bootdelay = bootdelay;
    
    	return s;
    }
    
    void autoboot_command(const char *s)
    {
    	debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
    
    	if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {
    #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
    		int prev = disable_ctrlc(1);	/* disable Control C checking */
    #endif
    
    		run_command_list(s, -1, 0);
    
    #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
    		disable_ctrlc(prev);	/* restore Control C checking */
    #endif
    	}
    
    #ifdef CONFIG_MENUKEY
    	if (menukey == CONFIG_MENUKEY) {
    		s = getenv("menucmd");
    		if (s)
    			run_command_list(s, -1, 0);
    	}
    #endif /* CONFIG_MENUKEY */
    }
    
    (proposed) board.c
    /*
     * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
     *
     * Author: Felipe Balbi <balbi@ti.com>
     *
     * Based on board/ti/dra7xx/evm.c
     *
     * SPDX-License-Identifier:	GPL-2.0+
     */
    
    #include <common.h>
    #include <palmas.h>
    #include <sata.h>
    #include <usb.h>
    #include <asm/omap_common.h>
    #include <asm/omap_sec_common.h>
    #include <asm/emif.h>
    #include <asm/gpio.h>
    #include <asm/arch/gpio.h>
    #include <asm/arch/clock.h>
    #include <asm/arch/dra7xx_iodelay.h>
    #include <asm/arch/sys_proto.h>
    #include <asm/arch/mmc_host_def.h>
    #include <asm/arch/sata.h>
    #include <asm/arch/gpio.h>
    #include <asm/arch/omap.h>
    #include <environment.h>
    #include <usb.h>
    #include <linux/usb/gadget.h>
    #include <dwc3-uboot.h>
    #include <dwc3-omap-uboot.h>
    #include <ti-usb-phy-uboot.h>
    
    #include "mux_data.h"
    #include "hw_info.h"
    
    #ifdef CONFIG_DRIVER_TI_CPSW
    #include <cpsw.h>
    #endif
    
    /* The processor supports both DDR-1066 & DDR-1333 and the installed DRAM
     * supports even higher speeds.  This board file was originally developed from
     * one supporting a TI evaluation board and needed to be changed to match the
     * RV700 HW.  The original change was an ugly hack whose effect was to select
     * DDR-1066.  When this code was later reviewed and the unfortunate speed
     * choice was discovered, it was decided that it was too late in the project
     * to risk changing to the higher speed and so the first version will ship
     * with DDR-1066.
     *
     * Note that there's a spec in the data sheet that implies that DDR-1333 isn't
     * supported however this was chased down with TI and that spec was determined
     * to be a typo.  By the time this comment is next read, it's possible that the
     * data sheet will have been updated to correct that error.
     *
     * Bottom line: at some future point when there's sufficient test time
     * available, it is probably worth selecting DDR-1333 for a 25% speed boost.
     */
    #define DRAM_SPEED 1066  /* 1.870 ns cyle time, CL = 7 */
    //#define DRAM_SPEED 1333  /* 1.500 ns cyle time, CL = 9 */
    
    DECLARE_GLOBAL_DATA_PTR;
    
    /* GPIO 7_11 */
    #define GPIO_DDR_VTT_EN 203
    
    #define SYSINFO_BOARD_NAME_MAX_LEN	45
    
    #define TPS65903X_PRIMARY_SECONDARY_PAD2	0xFB
    #define TPS65903X_PAD2_POWERHOLD_MASK		0x20
    
    /* MiiS@20200227 DarkHou add to fix some main board can't power on issue. TFS-Bug 11153 begin */
    #define OCMC_RAM1_REBOOT_REASON_ADDR  0x4035FF00  /* Chip ram address to save boot reason */
    #define REBOOT_BY_IO_CAL_ERROR        0x34562301  /* Reboot reason - I/O calibration failed */
    #define NORMAL_POWER_ON               0x32346643  /* Normal power on */
    /* MiiS@20200227 DarkHou add to fix some main board can't power on issue. TFS-Bug 11153 end */
    /* define "board info string": must start with "Board: " and end w/ '\n' */
    const struct omap_sysinfo sysinfo = {
    	"Board: RV700\n"
    };
    
    static const struct dmm_lisa_map_regs rv700_am5718_lisa_regs = {
    	.dmm_lisa_map_3 = 0x80700100,
    	.is_ma_present  = 0x1
    };
    
    void emif_get_dmm_regs(const struct dmm_lisa_map_regs **dmm_lisa_regs)
    {
    	*dmm_lisa_regs = &rv700_am5718_lisa_regs;		
    }
    
    static const struct emif_regs beagle_x15_emif1_ddr3_532mhz_emif_regs = {
    	.sdram_config_init		= 0x61851b32,
    	.sdram_config			= 0x61851b32,
    	.sdram_config2			= 0x08000000,
    	.ref_ctrl			= 0x000040F1,
    	.ref_ctrl_final			= 0x00001035,
    	.sdram_tim1			= 0xcccf36ab,
    	.sdram_tim2			= 0x308f7fda,
    	.sdram_tim3			= 0x409f88a8,
    	.read_idle_ctrl			= 0x00050000,
    	.zq_config			= 0x5007190b,
    	.temp_alert_config		= 0x00000000,
    	.emif_ddr_phy_ctlr_1_init 	= 0x0024400b,
    	.emif_ddr_phy_ctlr_1		= 0x0e24400b,
    	.emif_ddr_ext_phy_ctrl_1 	= 0x10040100,
    	.emif_ddr_ext_phy_ctrl_2 	= 0x00910091,
    	.emif_ddr_ext_phy_ctrl_3 	= 0x00950095,
    	.emif_ddr_ext_phy_ctrl_4 	= 0x009b009b,
    	.emif_ddr_ext_phy_ctrl_5 	= 0x009e009e,
    	.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		= 0x00000305
    };
    
    /* Ext phy ctrl regs 1-35 */
    static const u32 beagle_x15_emif1_ddr3_ext_phy_ctrl_const_regs[] = {
    	0x10040100,
    	0x00910091,
    	0x00950095,
    	0x009B009B,
    	0x009E009E,
    	0x00980098,
    	0x00340034,
    	0x00350035,
    	0x00340034,
    	0x00310031,
    	0x00340034,
    	0x007F007F,
    	0x007F007F,
    	0x007F007F,
    	0x007F007F,
    	0x007F007F,
    	0x00480048,
    	0x004A004A,
    	0x00520052,
    	0x00550055,
    	0x00500050,
    	0x00000000,
    	0x00600020,
    	0x40011080,
    	0x08102040,
    	0x0,
    	0x0,
    	0x0,
    	0x0,
    	0x0,
    	0x0,
    	0x0,
    	0x0,
    	0x0,
    	0x0
    };
    
    static const struct emif_regs beagle_x15_emif2_ddr3_532mhz_emif_regs = {
    	.sdram_config_init		= 0x61851b32,
    	.sdram_config			= 0x61851b32,
    	.sdram_config2			= 0x08000000,
    	.ref_ctrl			= 0x000040F1,
    	.ref_ctrl_final			= 0x00001035,
    	.sdram_tim1			= 0xcccf36b3,
    	.sdram_tim2			= 0x308f7fda,
    	.sdram_tim3			= 0x407f88a8,
    	.read_idle_ctrl			= 0x00050000,
    	.zq_config			= 0x5007190b,
    	.temp_alert_config		= 0x00000000,
    	.emif_ddr_phy_ctlr_1_init 	= 0x0024400b,
    	.emif_ddr_phy_ctlr_1		= 0x0e24400b,
    	.emif_ddr_ext_phy_ctrl_1 	= 0x10040100,
    	.emif_ddr_ext_phy_ctrl_2 	= 0x00910091,
    	.emif_ddr_ext_phy_ctrl_3 	= 0x00950095,
    	.emif_ddr_ext_phy_ctrl_4 	= 0x009b009b,
    	.emif_ddr_ext_phy_ctrl_5 	= 0x009e009e,
    	.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		= 0x00000305
    };
    
    static const u32 beagle_x15_emif2_ddr3_ext_phy_ctrl_const_regs[] = {
    	0x10040100,
    	0x00910091,
    	0x00950095,
    	0x009B009B,
    	0x009E009E,
    	0x00980098,
    	0x00340034,
    	0x00350035,
    	0x00340034,
    	0x00310031,
    	0x00340034,
    	0x007F007F,
    	0x007F007F,
    	0x007F007F,
    	0x007F007F,
    	0x007F007F,
    	0x00480048,
    	0x004A004A,
    	0x00520052,
    	0x00550055,
    	0x00500050,
    	0x00000000,
    	0x00600020,
    	0x40011080,
    	0x08102040,
    	0x0,
    	0x0,
    	0x0,
    	0x0,
    	0x0,
    	0x0,
    	0x0,
    	0x0,
    	0x0,
    	0x0
    };
    
    #if DRAM_SPEED == 1333
    static const struct emif_regs am571x_emif1_ddr3_666mhz_emif_regs = {
    	.sdram_config_init		= 0x61863332,
    	.sdram_config			= 0x61863332,
    	.sdram_config2			= 0x08000000,
    	.ref_ctrl			= 0x0000514d,
    	.ref_ctrl_final			= 0x0000144a,
    	.sdram_tim1			= 0xd333887c,
    	.sdram_tim2			= 0x40b37fe3,
    	.sdram_tim3			= 0x409f8ada,
    	.read_idle_ctrl			= 0x00050000,
    	.zq_config			= 0x5007190b,
    	.temp_alert_config		= 0x00000000,
    	.emif_ddr_phy_ctlr_1_init	= 0x0024400f,
    	.emif_ddr_phy_ctlr_1		= 0x0e24400f,
    	.emif_ddr_ext_phy_ctrl_1	= 0x10040100,
    	.emif_ddr_ext_phy_ctrl_2	= 0x00910091,
    	.emif_ddr_ext_phy_ctrl_3	= 0x00950095,
    	.emif_ddr_ext_phy_ctrl_4	= 0x009b009b,
    	.emif_ddr_ext_phy_ctrl_5	= 0x009e009e,
    	.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		= 0x00000305
    };
    #endif
    
    void emif_get_reg_dump(u32 emif_nr, const struct emif_regs **regs)
    {
    	switch (emif_nr) {
    	case 1:
    #if DRAM_SPEED == 1066
    		*regs = &beagle_x15_emif1_ddr3_532mhz_emif_regs;
    #elif DRAM_SPEED == 1333
    		*regs = &am571x_emif1_ddr3_666mhz_emif_regs;
    #else
        #error DRAM_SPEED not defined
    #endif
    		break;
    	case 2:
    		*regs = &beagle_x15_emif2_ddr3_532mhz_emif_regs;
    		break;
    	}
    }
    
    void emif_get_ext_phy_ctrl_const_regs(u32 emif_nr, const u32 **regs, u32 *size)
    {
    	switch (emif_nr) {
    	case 1:
    		*regs = beagle_x15_emif1_ddr3_ext_phy_ctrl_const_regs;
    		*size = ARRAY_SIZE(beagle_x15_emif1_ddr3_ext_phy_ctrl_const_regs);
    		break;
    	case 2:
    		*regs = beagle_x15_emif2_ddr3_ext_phy_ctrl_const_regs;
    		*size = ARRAY_SIZE(beagle_x15_emif2_ddr3_ext_phy_ctrl_const_regs);
    		break;
    	}
    }
    
    struct vcores_data rv700_volts = {
    	.mpu.value[OPP_NOM]	= VDD_MPU_DRA7_NOM,
    	.mpu.efuse.reg[OPP_NOM]	= STD_FUSE_OPP_VMIN_MPU_NOM,
    	.mpu.efuse.reg_bits     = DRA752_EFUSE_REGBITS,
    	.mpu.addr		= TPS659038_REG_ADDR_SMPS12,
    	.mpu.pmic		= &tps659038,
    	.mpu.abb_tx_done_mask	= OMAP_ABB_MPU_TXDONE_MASK,
    
    	.eve.value[OPP_NOM]	= VDD_EVE_DRA7_NOM,
    	.eve.value[OPP_OD]	= VDD_EVE_DRA7_OD,
    	.eve.value[OPP_HIGH]	= VDD_EVE_DRA7_HIGH,
    	.eve.efuse.reg[OPP_NOM]	= STD_FUSE_OPP_VMIN_DSPEVE_NOM,
    	.eve.efuse.reg[OPP_OD]	= STD_FUSE_OPP_VMIN_DSPEVE_OD,
    	.eve.efuse.reg[OPP_HIGH]	= STD_FUSE_OPP_VMIN_DSPEVE_HIGH,
    	.eve.efuse.reg_bits	= DRA752_EFUSE_REGBITS,
    	.eve.addr		= TPS659038_REG_ADDR_SMPS45,
    	.eve.pmic		= &tps659038,
    	.eve.abb_tx_done_mask	= OMAP_ABB_EVE_TXDONE_MASK,
    
    	.gpu.value[OPP_NOM]	= VDD_GPU_DRA7_NOM,
    	.gpu.value[OPP_OD]	= VDD_GPU_DRA7_OD,
    	.gpu.value[OPP_HIGH]	= VDD_GPU_DRA7_HIGH,
    	.gpu.efuse.reg[OPP_NOM]	= STD_FUSE_OPP_VMIN_GPU_NOM,
    	.gpu.efuse.reg[OPP_OD]	= STD_FUSE_OPP_VMIN_GPU_OD,
    	.gpu.efuse.reg[OPP_HIGH]	= STD_FUSE_OPP_VMIN_GPU_HIGH,
    	.gpu.efuse.reg_bits	= DRA752_EFUSE_REGBITS,
    	.gpu.addr		= TPS659038_REG_ADDR_SMPS45,
    	.gpu.pmic		= &tps659038,
    	.gpu.abb_tx_done_mask	= OMAP_ABB_GPU_TXDONE_MASK,
    
    	.core.value[OPP_NOM]	= VDD_CORE_DRA7_NOM,
    	.core.efuse.reg[OPP_NOM]	= STD_FUSE_OPP_VMIN_CORE_NOM,
    	.core.efuse.reg_bits	= DRA752_EFUSE_REGBITS,
    	.core.addr		= TPS659038_REG_ADDR_SMPS6,
    	.core.pmic		= &tps659038,
    
    	.iva.value[OPP_NOM]	= VDD_IVA_DRA7_NOM,
    	.iva.value[OPP_OD]	= VDD_IVA_DRA7_OD,
    	.iva.value[OPP_HIGH]	= VDD_IVA_DRA7_HIGH,
    	.iva.efuse.reg[OPP_NOM]	= STD_FUSE_OPP_VMIN_IVA_NOM,
    	.iva.efuse.reg[OPP_OD]	= STD_FUSE_OPP_VMIN_IVA_OD,
    	.iva.efuse.reg[OPP_HIGH]	= STD_FUSE_OPP_VMIN_IVA_HIGH,
    	.iva.efuse.reg_bits	= DRA752_EFUSE_REGBITS,
    	.iva.addr		= TPS659038_REG_ADDR_SMPS45,
    	.iva.pmic		= &tps659038,
    	.iva.abb_tx_done_mask	= OMAP_ABB_IVA_TXDONE_MASK,
    };
    
    int get_voltrail_opp(int rail_offset)
    {
    	int opp;
    
    	switch (rail_offset) {
    	case VOLT_MPU:
    		opp = DRA7_MPU_OPP;
    		break;
    	case VOLT_CORE:
    		opp = DRA7_CORE_OPP;
    		break;
    	case VOLT_GPU:
    		opp = DRA7_GPU_OPP;
    		break;
    	case VOLT_EVE:
    		opp = DRA7_DSPEVE_OPP;
    		break;
    	case VOLT_IVA:
    		opp = DRA7_IVA_OPP;
    		break;
    	default:
    		opp = OPP_NOM;
    	}
    
    	return opp;
    }
    
    void vcores_init(void)
    {
    	*omap_vcores = &rv700_volts;
    }
    
    void hw_data_init(void)
    {
    	*prcm = &dra7xx_prcm;
    #if DRAM_SPEED == 1066
    	*dplls_data = &dra7xx_dplls;
    #elif DRAM_SPEED == 1333
    	*dplls_data = &dra72x_dplls;
    #else
        #error DRAM_SPEED not defined
    #endif
    	*ctrl = &dra7xx_ctrl;
    }
    
    int board_init(void)
    {
    	gpmc_init();
    	gd->bd->bi_boot_params = (CONFIG_SYS_SDRAM_BASE + 0x100);
    
    	return 0;
    }
    
    int board_late_init(void)
    {
    	/*
    	 * DEV_CTRL.DEV_ON = 1 please - else palmas switches off in 8 seconds
    	 * This is the POWERHOLD-in-Low behavior.
    	 */
    	palmas_i2c_write_u8(TPS65903X_CHIP_P1, 0xA0, 0x1);
    
    	/*
    	 * Set the GPIO7 Pad to POWERHOLD. This has higher priority
    	 * over DEV_CTRL.DEV_ON bit. This can be reset in case of
    	 * PMIC Power off. So to be on the safer side set it back
    	 * to POWERHOLD mode irrespective of the current state.
    	 */
    	u8 val;
    	palmas_i2c_read_u8(TPS65903X_CHIP_P1, TPS65903X_PRIMARY_SECONDARY_PAD2,
    			   &val);
    	val = val | TPS65903X_PAD2_POWERHOLD_MASK;
    	palmas_i2c_write_u8(TPS65903X_CHIP_P1, TPS65903X_PRIMARY_SECONDARY_PAD2,
    			    val);
    
    #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_DRIVER_TI_CPSW)
    	board_ti_set_ethaddr(2);
    #endif
    
    	if (get_hw_version() > 0) {
    		const struct pad_conf_entry *pconf_hw_1_0;
    		int pconf_sz_hw_1_0;
    	
    		pconf_hw_1_0 = core_padconf_array_rv700_am5718_board_1_0;
    		pconf_sz_hw_1_0 =
    			ARRAY_SIZE(core_padconf_array_rv700_am5718_board_1_0);
    		do_set_mux32((*ctrl)->control_padconf_core_base,
    			     pconf_hw_1_0, pconf_sz_hw_1_0);
    	}
    	
    	return 0;
    }
    
    void set_muxconf_regs(void)
    {
    	do_set_mux32((*ctrl)->control_padconf_core_base,
    		     early_padconf, ARRAY_SIZE(early_padconf));
    }
    
    #ifdef CONFIG_IODELAY_RECALIBRATION
    void recalibrate_iodelay(void)
    {
    	const struct pad_conf_entry *pconf;
    	const struct iodelay_cfg_entry *iod;
    	int pconf_sz, iod_sz;
    	int ret;
    	int *reboot_reason = (int *) OCMC_RAM1_REBOOT_REASON_ADDR;
    
    	pconf = core_padconf_array_rv700_am5718_board_base;
    	pconf_sz = ARRAY_SIZE(core_padconf_array_rv700_am5718_board_base);
    
    	iod = iodelay_cfg_array_rv700_am5718_board_base;
    	iod_sz = ARRAY_SIZE(iodelay_cfg_array_rv700_am5718_board_base);
    	
    	// Setup I/O isolation 
    	ret = __recalibrate_iodelay_start();
    
            /* I/O Calibration failed */
    	if (ret) {
                    /* Set reboot reason as I/O calibration error at first time */
    		if (*reboot_reason != REBOOT_BY_IO_CAL_ERROR) {
    			*reboot_reason = REBOOT_BY_IO_CAL_ERROR;
    		}
                    /* Don't reboot again for second I/O calibration failed case */
    		else
    		{
    			*reboot_reason = NORMAL_POWER_ON;
    		}
    	}
            /* I/O Calibration sucucess*/
    	else
    	{
                    /* Set reboot reason as normal power on */
    		*reboot_reason = NORMAL_POWER_ON;
    	}
    
    	/* Do the muxing here */
    	do_set_mux32((*ctrl)->control_padconf_core_base, pconf, pconf_sz);
    
    	/* Setup IOdelay configuration */
    	ret = do_set_iodelay((*ctrl)->iodelay_config_base, iod, iod_sz);
    
    	/* Closeup.. remove isolation */
    	__recalibrate_iodelay_end(ret);
    }
    #endif
    
    #if defined(CONFIG_GENERIC_MMC)
    int board_mmc_init(bd_t *bis)
    {
    	omap_mmc_init(0, 0, 0, -1, -1);
    	omap_mmc_init(1, 0, 0, -1, -1);
    	return 0;
    }
    #endif
    
    #if defined(CONFIG_IODELAY_RECALIBRATION) && \
    	(defined(CONFIG_SPL_BUILD) || !defined(CONFIG_DM_MMC))
    
    struct pinctrl_desc {
    	const char *name;
    	struct omap_hsmmc_pinctrl_state *pinctrl;
    };
    
    static struct pinctrl_desc pinctrl_descs_hsmmc1[] = {
    	{"default", &hsmmc1_default},
    	{"hs", &hsmmc1_default},
    	{NULL}
    };
    
    static struct pinctrl_desc pinctrl_descs_hsmmc2_am571[] = {
    	{"default", &hsmmc2_default_hs},
    	{"hs", &hsmmc2_default_hs},
    	{"ddr_1_8v", &hsmmc2_ddr_am571},
    	{NULL}
    };
    
    struct omap_hsmmc_pinctrl_state *platform_fixup_get_pinctrl_by_mode
    				  (struct hsmmc *base, const char *mode)
    {
    	struct pinctrl_desc *p = NULL;
    
    	switch ((u32)&base->res1) {
    	case OMAP_HSMMC1_BASE:
    		p = pinctrl_descs_hsmmc1;
    		break;
    	case OMAP_HSMMC2_BASE:
    		p = pinctrl_descs_hsmmc2_am571;
    	default:
    		break;
    	}
    
    	if (!p) {
    		printf("%s no pinctrl defined for MMC@%p\n", __func__,
    		       base);
    		return NULL;
    	}
    	while (p->name) {
    		if (strcmp(mode, p->name) == 0)
    			return p->pinctrl;
    		p++;
    	}
    	return NULL;
    }
    #endif
    
    #ifdef CONFIG_OMAP_HSMMC
    int platform_fixup_disable_uhs_mode(void)
    {
    	return omap_revision() == DRA752_ES1_1;
    }
    #endif
    
    #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_OS_BOOT)
    int spl_start_uboot(void)
    {
    	/* break into full u-boot on 'c' */
    	if (serial_tstc() && serial_getc() == 'c')
    		return 1;
    
    #ifdef CONFIG_SPL_ENV_SUPPORT
    	env_init();
    	env_relocate_spec();
    	if (getenv_yesno("boot_os") != 1)
    		return 1;
    #endif
    
    	return 0;
    }
    #endif
    
    #ifdef CONFIG_USB_DWC3
    static struct dwc3_device usb_otg_ss2 = {
    	.maximum_speed = USB_SPEED_HIGH,
    	.base = DRA7_USB_OTG_SS2_BASE,
    	.tx_fifo_resize = false,
    	.index = 1,
    };
    
    static struct dwc3_omap_device usb_otg_ss2_glue = {
    	.base = (void *)DRA7_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 *)DRA7_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);
    	switch (index) {
    	case 0:
    		if (init == USB_INIT_DEVICE) {
    			printf("port %d can't be used as device\n", index);
    			disable_usb_clocks(index);
    			return -EINVAL;
    		}
    		break;
    	case 1:
    		if (init == USB_INIT_DEVICE) {
    #ifdef CONFIG_USB_DWC3
    			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);
    #endif
    		} else {
    			printf("port %d can't be used as host\n", index);
    			disable_usb_clocks(index);
    			return -EINVAL;
    		}
    
    		break;
    	default:
    		printf("Invalid Controller Index\n");
    	}
    
    	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) */
    
    #ifdef CONFIG_DRIVER_TI_CPSW
    
    /* Delay value to add to calibrated value */
    #define RGMII0_TXCTL_DLY_VAL		((0x3 << 5) + 0x8)
    #define RGMII0_TXD0_DLY_VAL		((0x3 << 5) + 0x8)
    #define RGMII0_TXD1_DLY_VAL		((0x3 << 5) + 0x2)
    #define RGMII0_TXD2_DLY_VAL		((0x4 << 5) + 0x0)
    #define RGMII0_TXD3_DLY_VAL		((0x4 << 5) + 0x0)
    #define VIN2A_D13_DLY_VAL		((0x3 << 5) + 0x8)
    #define VIN2A_D17_DLY_VAL		((0x3 << 5) + 0x8)
    #define VIN2A_D16_DLY_VAL		((0x3 << 5) + 0x2)
    #define VIN2A_D15_DLY_VAL		((0x4 << 5) + 0x0)
    #define VIN2A_D14_DLY_VAL		((0x4 << 5) + 0x0)
    
    static void cpsw_control(int enabled)
    {
    	/* VTP can be added here */
    }
    
    static struct cpsw_slave_data cpsw_slaves[] = {
    	{
    		.slave_reg_ofs	= 0x208,
    		.sliver_reg_ofs	= 0xd80,
    		.phy_addr	= 1,
    	},
    	{
    		.slave_reg_ofs	= 0x308,
    		.sliver_reg_ofs	= 0xdc0,
    		.phy_addr	= 2,
    	},
    };
    
    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,
    };
    
    static u64 mac_to_u64(u8 mac[6])
    {
    	int i;
    	u64 addr = 0;
    
    	for (i = 0; i < 6; i++) {
    		addr <<= 8;
    		addr |= mac[i];
    	}
    
    	return addr;
    }
    
    static void u64_to_mac(u64 addr, u8 mac[6])
    {
    	mac[5] = addr;
    	mac[4] = addr >> 8;
    	mac[3] = addr >> 16;
    	mac[2] = addr >> 24;
    	mac[1] = addr >> 32;
    	mac[0] = addr >> 40;
    }
    
    int board_eth_init(bd_t *bis)
    {
    	int ret;
    	uint8_t mac_addr[6];
    	uint32_t mac_hi, mac_lo;
    	uint32_t ctrl_val;
    	int i;
    	u64 mac1, mac2;
    	u8 mac_addr1[6], mac_addr2[6];
    	int num_macs;
    
    	/* try reading mac address from efuse */
    	mac_lo = readl((*ctrl)->control_core_mac_id_0_lo);
    	mac_hi = readl((*ctrl)->control_core_mac_id_0_hi);
    	mac_addr[0] = (mac_hi & 0xFF0000) >> 16;
    	mac_addr[1] = (mac_hi & 0xFF00) >> 8;
    	mac_addr[2] = mac_hi & 0xFF;
    	mac_addr[3] = (mac_lo & 0xFF0000) >> 16;
    	mac_addr[4] = (mac_lo & 0xFF00) >> 8;
    	mac_addr[5] = mac_lo & 0xFF;
    
    	if (!getenv("ethaddr")) {
    		printf("<ethaddr> not set. Validating first E-fuse MAC\n");
    
    		if (is_valid_ethaddr(mac_addr))
    			eth_setenv_enetaddr("ethaddr", mac_addr);
    	}
    
    	mac_lo = readl((*ctrl)->control_core_mac_id_1_lo);
    	mac_hi = readl((*ctrl)->control_core_mac_id_1_hi);
    	mac_addr[0] = (mac_hi & 0xFF0000) >> 16;
    	mac_addr[1] = (mac_hi & 0xFF00) >> 8;
    	mac_addr[2] = mac_hi & 0xFF;
    	mac_addr[3] = (mac_lo & 0xFF0000) >> 16;
    	mac_addr[4] = (mac_lo & 0xFF00) >> 8;
    	mac_addr[5] = mac_lo & 0xFF;
    
    	if (!getenv("eth1addr")) {
    		if (is_valid_ethaddr(mac_addr))
    			eth_setenv_enetaddr("eth1addr", mac_addr);
    	}
    
    	ctrl_val = readl((*ctrl)->control_core_control_io1) & (~0x33);
    	ctrl_val |= 0x22;
    	writel(ctrl_val, (*ctrl)->control_core_control_io1);
    
    	ret = cpsw_register(&cpsw_data);
    	if (ret < 0)
    		printf("Error %d registering CPSW switch\n", ret);
    
    	/*
    	 * Export any Ethernet MAC addresses from EEPROM.
    	 * On AM57xx the 2 MAC addresses define the address range
    	 */
    	board_ti_get_eth_mac_addr(0, mac_addr1);
    	board_ti_get_eth_mac_addr(1, mac_addr2);
    
    	if (is_valid_ethaddr(mac_addr1) && is_valid_ethaddr(mac_addr2)) {
    		mac1 = mac_to_u64(mac_addr1);
    		mac2 = mac_to_u64(mac_addr2);
    
    		/* must contain an address range */
    		num_macs = mac2 - mac1 + 1;
    		/* <= 50 to protect against user programming error */
    		if (num_macs > 0 && num_macs <= 50) {
    			for (i = 0; i < num_macs; i++) {
    				u64_to_mac(mac1 + i, mac_addr);
    				if (is_valid_ethaddr(mac_addr)) {
    					eth_setenv_enetaddr_by_index("eth",
    								     i + 2,
    								     mac_addr);
    				}
    			}
    		}
    	}
    
    	return ret;
    }
    #endif /* CONFIG_DRIVER_TI_CPSW */
    
    #ifdef CONFIG_BOARD_EARLY_INIT_F
    /* VTT regulator enable */
    static inline void vtt_regulator_enable(void)
    {
    	if (omap_hw_init_context() == OMAP_INIT_CONTEXT_UBOOT_AFTER_SPL)
    		return;
    
    	gpio_request(GPIO_DDR_VTT_EN, "ddr_vtt_en");
    	gpio_direction_output(GPIO_DDR_VTT_EN, 1);
    }
    
    int board_early_init_f(void)
    {
    	vtt_regulator_enable();
    	return 0;
    }
    #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_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
    

    Again, appreciate any guidance or input.

    Regards,

    Chris

  • Can you provide more details on the statement "They are failing the TI recommended I/O calibration."  What register/value are they using to determine failure?

  • B.C.,

    In the Board.c file they rely on:

            ret = __recalibrate_iodelay_start();

            if (ret) {

    failing. (ret NE 0)

    Thanks,

    Chris

  • Can they dig deeper in the code to determine exactly which register read is the issue?