Skip to content
Snippets Groups Projects
ddr3_read_leveling.c 34 KiB
Newer Older
/*
 * Copyright (C) Marvell International Ltd. and its affiliates
 *
 * SPDX-License-Identifier:	GPL-2.0
 */

#include <common.h>
#include <i2c.h>
#include <spl.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>

#include "ddr3_hw_training.h"

/*
 * Debug
 */
#define DEBUG_RL_C(s, d, l) \
	DEBUG_RL_S(s); DEBUG_RL_D(d, l); DEBUG_RL_S("\n")
#define DEBUG_RL_FULL_C(s, d, l) \
	DEBUG_RL_FULL_S(s); DEBUG_RL_FULL_D(d, l); DEBUG_RL_FULL_S("\n")

#ifdef MV_DEBUG_RL
#define DEBUG_RL_S(s) \
	debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%s", s)
#define DEBUG_RL_D(d, l) \
	debug_cond(ddr3_get_log_level() >= MV_LOG_LEVEL_2, "%x", d)
#else
#define DEBUG_RL_S(s)
#define DEBUG_RL_D(d, l)
#endif

#ifdef MV_DEBUG_RL_FULL
#define DEBUG_RL_FULL_S(s)		puts(s)
#define DEBUG_RL_FULL_D(d, l)		printf("%x", d)
#else
#define DEBUG_RL_FULL_S(s)
#define DEBUG_RL_FULL_D(d, l)
#endif

extern u32 rl_pattern[LEN_STD_PATTERN];

#ifdef RL_MODE
static int ddr3_read_leveling_single_cs_rl_mode(u32 cs, u32 freq,
						int ratio_2to1, u32 ecc,
						MV_DRAM_INFO *dram_info);
#else
static int ddr3_read_leveling_single_cs_window_mode(u32 cs, u32 freq,
						    int ratio_2to1, u32 ecc,
						    MV_DRAM_INFO *dram_info);
#endif

/*
 * Name:     ddr3_read_leveling_hw
 * Desc:     Execute the Read leveling phase by HW
 * Args:     dram_info - main struct
 *           freq      - current sequence frequency
 * Notes:
 * Returns:  MV_OK if success, MV_FAIL if fail.
 */
int ddr3_read_leveling_hw(u32 freq, MV_DRAM_INFO *dram_info)
{
	u32 reg;

	/* Debug message - Start Read leveling procedure */
	DEBUG_RL_S("DDR3 - Read Leveling - Starting HW RL procedure\n");

	/* Start Auto Read Leveling procedure */
	reg = 1 << REG_DRAM_TRAINING_RL_OFFS;
	/* Config the retest number */
	reg |= (COUNT_HW_RL << REG_DRAM_TRAINING_RETEST_OFFS);

	/* Enable CS in the automatic process */
	reg |= (dram_info->cs_ena << REG_DRAM_TRAINING_CS_OFFS);

	reg_write(REG_DRAM_TRAINING_ADDR, reg);	/* 0x15B0 - Training Register */

	reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) |
		(1 << REG_DRAM_TRAINING_AUTO_OFFS);
	reg_write(REG_DRAM_TRAINING_SHADOW_ADDR, reg);

	/* Wait */
	do {
		reg = reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) &
			(1 << REG_DRAM_TRAINING_AUTO_OFFS);
	} while (reg);		/* Wait for '0' */

	/* Check if Successful */
	if (reg_read(REG_DRAM_TRAINING_SHADOW_ADDR) &
	    (1 << REG_DRAM_TRAINING_ERROR_OFFS)) {
		u32 delay, phase, pup, cs;

		dram_info->rl_max_phase = 0;
		dram_info->rl_min_phase = 10;

		/* Read results to arrays */
		for (cs = 0; cs < MAX_CS; cs++) {
			if (dram_info->cs_ena & (1 << cs)) {
				for (pup = 0;
				     pup < dram_info->num_of_total_pups;
				     pup++) {
					if (pup == dram_info->num_of_std_pups
					    && dram_info->ecc_ena)
						pup = ECC_PUP;
					reg =
					    ddr3_read_pup_reg(PUP_RL_MODE, cs,
							      pup);
					phase = (reg >> REG_PHY_PHASE_OFFS) &
						PUP_PHASE_MASK;
					delay = reg & PUP_DELAY_MASK;
					dram_info->rl_val[cs][pup][P] = phase;
					if (phase > dram_info->rl_max_phase)
						dram_info->rl_max_phase = phase;
					if (phase < dram_info->rl_min_phase)
						dram_info->rl_min_phase = phase;
					dram_info->rl_val[cs][pup][D] = delay;
					dram_info->rl_val[cs][pup][S] =
					    RL_FINAL_STATE;
					reg =
					    ddr3_read_pup_reg(PUP_RL_MODE + 0x1,
							      cs, pup);
					dram_info->rl_val[cs][pup][DQS] =
					    (reg & 0x3F);
				}
#ifdef MV_DEBUG_RL
				/* Print results */
				DEBUG_RL_C("DDR3 - Read Leveling - Results for CS - ",
					   (u32) cs, 1);

				for (pup = 0;
				     pup < (dram_info->num_of_total_pups);
				     pup++) {
					if (pup == dram_info->num_of_std_pups
					    && dram_info->ecc_ena)
						pup = ECC_PUP;
					DEBUG_RL_S("DDR3 - Read Leveling - PUP: ");
					DEBUG_RL_D((u32) pup, 1);
					DEBUG_RL_S(", Phase: ");
					DEBUG_RL_D((u32) dram_info->
						   rl_val[cs][pup][P], 1);
					DEBUG_RL_S(", Delay: ");
					DEBUG_RL_D((u32) dram_info->
						   rl_val[cs][pup][D], 2);
					DEBUG_RL_S("\n");
				}
#endif
			}
		}

		dram_info->rd_rdy_dly =
			reg_read(REG_READ_DATA_READY_DELAYS_ADDR) &
			REG_READ_DATA_SAMPLE_DELAYS_MASK;
		dram_info->rd_smpl_dly =
			reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR) &
			REG_READ_DATA_READY_DELAYS_MASK;
#ifdef MV_DEBUG_RL
		DEBUG_RL_C("DDR3 - Read Leveling - Read Sample Delay: ",
			   dram_info->rd_smpl_dly, 2);
		DEBUG_RL_C("DDR3 - Read Leveling - Read Ready Delay: ",
			   dram_info->rd_rdy_dly, 2);
		DEBUG_RL_S("DDR3 - Read Leveling - HW RL Ended Successfully\n");
#endif
		return MV_OK;

	} else {
		DEBUG_RL_S("DDR3 - Read Leveling - HW RL Error\n");
		return MV_FAIL;
	}
}

/*
 * Name:     ddr3_read_leveling_sw
 * Desc:     Execute the Read leveling phase by SW
 * Args:     dram_info - main struct
 *           freq      - current sequence frequency
 * Notes:
 * Returns:  MV_OK if success, MV_FAIL if fail.
 */
int ddr3_read_leveling_sw(u32 freq, int ratio_2to1, MV_DRAM_INFO *dram_info)
{
	u32 reg, cs, ecc, pup_num, phase, delay, pup;
	int status;

	/* Debug message - Start Read leveling procedure */
	DEBUG_RL_S("DDR3 - Read Leveling - Starting SW RL procedure\n");

	/* Enable SW Read Leveling */
	reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
		(1 << REG_DRAM_TRAINING_2_SW_OVRD_OFFS);
	reg &= ~(1 << REG_DRAM_TRAINING_2_RL_MODE_OFFS);
	/* [0]=1 - Enable SW override  */
	/* 0x15B8 - Training SW 2 Register */
	reg_write(REG_DRAM_TRAINING_2_ADDR, reg);

#ifdef RL_MODE
	reg = (dram_info->cs_ena << REG_DRAM_TRAINING_CS_OFFS) |
		(1 << REG_DRAM_TRAINING_AUTO_OFFS);
	reg_write(REG_DRAM_TRAINING_ADDR, reg);	/* 0x15B0 - Training Register */
#endif
Loading
Loading full blame...