[coreboot-gerrit] Change in coreboot[master]: mediatek/mt8183: Add DDR driver of rx dqs gating calibration part

Tristan Hsieh (Code Review) gerrit at coreboot.org
Mon Oct 1 06:44:03 CEST 2018


Tristan Hsieh has uploaded this change for review. ( https://review.coreboot.org/28841


Change subject: mediatek/mt8183: Add DDR driver of rx dqs gating calibration part
......................................................................

mediatek/mt8183: Add DDR driver of rx dqs gating calibration part

BUG=b:80501386
BRANCH=none
TEST=Boots correctly on Kukui, and inits DRAM successfully with related
     patches.

Change-Id: I504d6d5c9ea01b11a9f2a05b5ee4b5f1af87e23f
Signed-off-by: Huayang Duan <huayang.duan at mediatek.com>
---
M src/soc/mediatek/mt8183/dramc_pi_basic_api.c
M src/soc/mediatek/mt8183/dramc_pi_calibration_api.c
M src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h
3 files changed, 666 insertions(+), 0 deletions(-)



  git pull ssh://review.coreboot.org:29418/coreboot refs/changes/41/28841/1

diff --git a/src/soc/mediatek/mt8183/dramc_pi_basic_api.c b/src/soc/mediatek/mt8183/dramc_pi_basic_api.c
index 4c95814..74eddd5 100644
--- a/src/soc/mediatek/mt8183/dramc_pi_basic_api.c
+++ b/src/soc/mediatek/mt8183/dramc_pi_basic_api.c
@@ -19,6 +19,16 @@
 #include <soc/dramc_register.h>
 #include <soc/dramc_pi_api.h>
 
+void dramc_save_restore_multi_reg(u8 type, u32 *store_mem,
+		u32 **addr, u32 count)
+{
+	for (int i = 0; i < count; i++)
+		if (type == SAVE_VALUE)
+			store_mem[i] = read32(addr[i]);
+		else
+			write32(addr[i], store_mem[i]);
+}
+
 static void sw_imp_cal_vref_sel(u8 term_option, u8 impcal_stage)
 {
 	u8 vref_sel = 0;
diff --git a/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c b/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c
index 7b42287..159d72a 100644
--- a/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c
+++ b/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c
@@ -310,6 +310,657 @@
 	}
 }
 
+static void rx_dqs_isi_pulse_cg_switch(u8 chn, u8 flag)
+{
+	dramc_dbg("CH%d RX DQS ISI pulse CG: %s\n", chn,
+		(flag == ENABLE) ? "enable" : "disable");
+
+	clrsetbits_le32(&ch[chn].phy.b[0].dq[6], 1 << 5, flag << 5);
+	clrsetbits_le32(&ch[chn].phy.b[1].dq[6], 1 << 5, flag << 5);
+}
+
+static void dramc_set_rank_engine2(u8 chn, u8 rank)
+{
+	setbits_le32(&ch[chn].ao.dramctrl, 0x1 << 1);
+	clrbits_le32(&ch[chn].ao.test2_4, TEST2_4_TESTAGENTRKSEL_MASK);
+	clrsetbits_le32(&ch[chn].ao.test2_4, TEST2_4_TESTAGENTRK_MASK,
+		rank << TEST2_4_TESTAGENTRK_SHIFT);
+}
+
+static void dramc_engine2_init(u8 chn, u8 rank, u32 size, u8 testaudpat)
+{
+	const u32 pat0 = 0x55;
+	const u32 pat1 = 0xaa;
+	const u32 addr = 0;
+	const u32 log2loopcount = 0;
+
+	dramc_set_rank_engine2(chn, rank);
+
+	clrbits_le32(&ch[chn].ao.dummy_rd,
+		 (0x1 << DUMMY_RD_DQSG_DMYRD_EN_SHIFT) |
+		 (0x1 << DUMMY_RD_DQSG_DMYWR_EN_SHIFT) |
+		 (0x1 << DUMMY_RD_DUMMY_RD_EN_SHIFT) |
+		 (0x1 << DUMMY_RD_SREF_DMYRD_EN_SHIFT) |
+		 (0x1 << DUMMY_RD_DMY_RD_DBG_SHIFT) |
+		 (0x1 << DUMMY_RD_DMY_WR_DBG_SHIFT));
+	clrbits_le32(&ch[chn].nao.testchip_dma1,
+		0x1 << TESTCHIP_DMA1_DMA_LP4MATAB_OPT_SHIFT);
+	clrsetbits_le32(&ch[chn].ao.test2_3,
+		 (0x1 << TEST2_3_TEST2W_SHIFT) |
+		 (0x1 << TEST2_3_TEST2R_SHIFT) |
+		 (0x1 << TEST2_3_TEST1_SHIFT) |
+		 (0x1 << TEST2_3_TESTAUDPAT_SHIFT) |
+		 TEST2_3_TESTCNT_MASK,
+		 log2loopcount << TEST2_3_TESTCNT_SHIFT |
+		((testaudpat ? 1 : 0) << TEST2_3_TESTAUDPAT_SHIFT));
+	clrsetbits_le32(&ch[chn].ao.test2_0,
+		TEST2_0_PAT0_MASK | TEST2_0_PAT1_MASK,
+		(pat0 << TEST2_0_PAT0_SHIFT) |
+		(pat1 << TEST2_0_PAT1_SHIFT));
+	write32(&ch[chn].ao.test2_1, (addr << 4) & 0x00ffffff);
+	write32(&ch[chn].ao.test2_2, (size << 4) & 0x00ffffff);
+
+	clrsetbits_le32(&ch[chn].ao.test2_4,
+		(0x1 << TEST2_4_TESTAUDMODE_SHIFT) |
+		(0x1 << TEST2_4_TESTAUDBITINV_SHIFT) |
+		(0x1 << TEST2_4_TESTXTALKPAT_SHIFT),
+		(((testaudpat == 0) ? 1 : 0) << TEST2_4_TESTXTALKPAT_SHIFT) |
+		(testaudpat << TEST2_4_TESTAUDMODE_SHIFT) |
+		(testaudpat << TEST2_4_TESTAUDBITINV_SHIFT));
+
+	if (testaudpat == 0) {
+		clrbits_le32(&ch[chn].ao.test2_4,
+			0x1 << TEST2_4_TEST_REQ_LEN1_SHIFT |
+			(0x1 << TEST2_4_TESTSSOPAT_SHIFT) |
+			(0x1 << TEST2_4_TESTSSOXTALKPAT_SHIFT));
+		setbits_le32(&ch[chn].ao.perfctl0,
+			0x1 << PERFCTL0_RWOFOEN_SHIFT);
+	} else if (testaudpat == 1) {
+		clrsetbits_le32(&ch[chn].ao.test2_4,
+			TEST2_4_TESTAUDINIT_MASK | TEST2_4_TESTAUDINC_MASK,
+			(0x11 << TEST2_4_TESTAUDINIT_SHIFT) |
+			(0xd << TEST2_4_TESTAUDINC_SHIFT));
+	}
+}
+
+static void dramc_engine2_check_complete(u8 chn)
+{
+	u32 u4loop_count = 0;
+	while ((read32(&ch[chn].nao.testrpt) & (0x1 << 0)) == 0) {
+		udelay(1);
+		u4loop_count++;
+
+		if (u4loop_count > MAX_CMP_CPT_WAIT_LOOP) {
+			dramc_dbg("MEASURE_A timeout\n");
+			break;
+		}
+	}
+}
+
+static u32 dramc_engine2_run(u8 chn, enum dram_te_op wr)
+{
+	u32 u4result = 0xffffffff;
+
+	if (wr == TE_OP_READ_CHECK) {
+		clrbits_le32(&ch[chn].ao.test2_4,
+			0x1 << TEST2_4_TESTAUDMODE_SHIFT);
+	} else if (wr == TE_OP_WRITE_READ_CHECK) {
+		clrsetbits_le32(&ch[chn].ao.test2_3,
+			(0x1 << TEST2_3_TEST2R_SHIFT) |
+			(0x1 << TEST2_3_TEST1_SHIFT),
+			0x1 << TEST2_3_TEST2W_SHIFT);
+
+		dramc_engine2_check_complete(chn);
+		clrbits_le32(&ch[chn].ao.test2_3,
+			 (0x1 << TEST2_3_TEST2W_SHIFT) |
+			 (0x1 << TEST2_3_TEST2R_SHIFT) |
+			 0x1 << TEST2_3_TEST1_SHIFT);
+		udelay(1);
+	}
+
+	/* do Read test */
+	clrsetbits_le32(&ch[chn].ao.test2_3,
+		(0x1 << TEST2_3_TEST2W_SHIFT) | (0x1 << TEST2_3_TEST1_SHIFT),
+		0x1 << TEST2_3_TEST2R_SHIFT);
+
+	dramc_engine2_check_complete(chn);
+
+	udelay(1);
+	u4result = read32(&ch[chn].nao.cmp_err);
+	clrbits_le32(&ch[chn].ao.test2_3,
+		 (0x1 << TEST2_3_TEST2W_SHIFT) |
+		 (0x1 << TEST2_3_TEST2R_SHIFT) |
+		 (0x1 << TEST2_3_TEST1_SHIFT));
+
+	return u4result;
+}
+
+static void dramc_engine2_end(u8 chn)
+{
+	clrbits_le32(&ch[chn].ao.test2_4, 0x1 << 17);
+}
+
+static void find_gating_window(u32 result_r, u32 result_f, u32 *debug_cnt,
+		u8 dly_coarse_large, u8 dly_coarse_0p5t, u8 *pass_begin,
+		u8 *pass_count, u8 *dly_fine_xt, u32 *coarse_tune, u8 *dqs_high)
+{
+	u16 debug_cnt_perbyte;
+	u8 pass_count_1[DQS_NUMBER], min_coarse_tune2t_1[DQS_NUMBER],
+	    min_coarse_tune0p5t_1[DQS_NUMBER], min_fine_tune_1[DQS_NUMBER];
+
+	for (u8 dqs = 0; dqs < DQS_NUMBER; dqs++) {
+		u8 dqs_result_r = (u8) ((result_r >> (8 * dqs)) & 0xff);
+		u8 dqs_result_f = (u8) ((result_f >> (8 * dqs)) & 0xff);
+		debug_cnt_perbyte = (u16) debug_cnt[dqs];
+
+		if ((dqs_result_r == 0) && (dqs_result_f == 0) &&
+		    (debug_cnt_perbyte == GATING_GOLDEND_DQSCNT)) {
+			if (pass_begin[dqs] == 0) {
+				pass_begin[dqs] = 1;
+				pass_count_1[dqs] = 0;
+				min_coarse_tune2t_1[dqs] = dly_coarse_large;
+				min_coarse_tune0p5t_1[dqs] = dly_coarse_0p5t;
+				min_fine_tune_1[dqs] = *dly_fine_xt;
+				dramc_dbg("[Byte %d]First pass (%d, %d, %d)\n",
+					dqs, dly_coarse_large,
+					dly_coarse_0p5t, *dly_fine_xt);
+			}
+
+			if (pass_begin[dqs] == 1)
+				pass_count_1[dqs]++;
+
+			if ((pass_begin[dqs] == 1) &&
+			    (pass_count_1[dqs] * DQS_GW_FINE_STEP > 32))
+				dqs_high[dqs] = 0;
+
+			if ((pass_count_1[0] * DQS_GW_FINE_STEP > 32) &&
+			    (pass_count_1[1] * DQS_GW_FINE_STEP > 32)) {
+				dramc_dbg("All bytes gating window > 1 "
+					"coarse_tune, Early break\n");
+				*dly_fine_xt = 32;
+				*coarse_tune = 42;
+			}
+		}
+	}
+}
+
+static void find_dly_tune(u8 chn, u8 dly_coarse_large, u8 dly_coarse_0p5t,
+		u8 dly_fine_xt, u8 *dqs_high, u8 *dly_coarse_large_cnt,
+		u8 *dly_coarse_0p5t_cnt, u8 *dly_fine_tune_cnt, u8 *dqs_trans)
+{
+	for (u8 dqs = 0; dqs < DQS_NUMBER; dqs++) {
+		u32 dqs_cnt = read32(&ch[chn].phy_nao.misc_phy_stben_b[dqs]);
+		dqs_cnt = (dqs_cnt >> 16) & 3;
+
+		if (dqs_cnt == 3)
+			dqs_high[dqs]++;
+
+		if (dqs_high[dqs] * DQS_GW_FINE_STEP <= 16)
+			continue;
+
+		switch (dqs_cnt) {
+		case 3:
+			dly_coarse_large_cnt[dqs] = dly_coarse_large;
+			dly_coarse_0p5t_cnt[dqs] = dly_coarse_0p5t;
+			dly_fine_tune_cnt[dqs] = dly_fine_xt;
+			dqs_trans[dqs] = 1;
+			break;
+		case 2:
+		case 1:
+			dqs_trans[dqs]++;
+			break;
+		case 0:
+			dqs_high[dqs] = 0;
+			break;
+		}
+	}
+}
+
+static void dram_phy_reset(u8 chn)
+{
+	setbits_le32(&ch[chn].ao.ddrconf0, 1 << DDRCONF0_RDATRST_SHIFT);
+	setbits_le32(&ch[chn].phy.misc_ctrl1, 1 << MISC_CTRL1_R_DMPHYRST_SHIFT);
+	clrbits_le32(&ch[chn].phy.b[0].dq[9], (1 << 4) | (1 << 0));
+	clrbits_le32(&ch[chn].phy.b[1].dq[9], (1 << 4) | (1 << 0));
+
+	udelay(1);
+	setbits_le32(&ch[chn].phy.b[1].dq[9], (1 << 4) | (1 << 0));
+	setbits_le32(&ch[chn].phy.b[0].dq[9], (1 << 4) | (1 << 0));
+	clrbits_le32(&ch[chn].phy.misc_ctrl1, 1 << MISC_CTRL1_R_DMPHYRST_SHIFT);
+	clrbits_le32(&ch[chn].ao.ddrconf0, 1 << DDRCONF0_RDATRST_SHIFT);
+}
+
+static void dramc_set_gating_mode(u8 chn, u8 mode)
+{
+	u8 vref = 0, burst = 0;
+
+	if (mode) {
+		vref = 2;
+		burst = 1;
+	}
+
+	clrsetbits_le32(&ch[chn].ao.stbcal1, 0x1 << 5, burst << 5);
+	setbits_le32(&ch[chn].ao.stbcal, 0x1 << 30);
+
+	for (u8 b = 0; b < 2; b++) {
+		clrsetbits_le32(&ch[chn].phy.b[b].dq[6], 0x3 << 14, vref << 14);
+		setbits_le32(&ch[chn].phy.b[b].dq[9], 0x1 << 5);
+		clrbits_le32(&ch[chn].phy.b[b].dq[9], (0x1 << 4) | (0x1 << 0));
+		setbits_le32(&ch[chn].phy.b[b].dq[9], (0x1 << 4) | (0x1 << 0));
+	}
+}
+
+static void dramc_rx_dqs_gating_cal(u8 chn, u8 rank)
+{
+	u8 pass_begin[DQS_NUMBER], pass_count[DQS_NUMBER];
+	u8 min_coarse_tune2t[DQS_NUMBER], min_coarse_tune0p5t[DQS_NUMBER],
+		min_fine_tune[DQS_NUMBER];
+	u8 best_fine_tune[DQS_NUMBER], best_coarse_tune0p5t[DQS_NUMBER],
+		best_coarse_tune2t[DQS_NUMBER];
+	u8 best_fine_tune_p1[DQS_NUMBER], best_coarse_tune0p5t_p1[DQS_NUMBER],
+		best_coarse_tune2t_p1[DQS_NUMBER];
+
+	u8 best_coarse_large_rodt[DQS_NUMBER],
+		best_coarse_0p5t_rodt[DQS_NUMBER];
+	u8 best_coarse_large_rodt_p1[DQS_NUMBER],
+		best_coarse_0p5t_rodt_p1[DQS_NUMBER];
+	u32 coarse_start = 18, coarse_end = coarse_start + 24;
+	u32 debug_cnt[DQS_NUMBER];
+
+	u8 dqs_high[DQS_NUMBER], dqs_transition[DQS_NUMBER];
+	u8 dly_coarse_large_cnt[DQS_NUMBER], dly_coarse_0p5t_cnt[DQS_NUMBER],
+		dly_fine_tune_cnt[DQS_NUMBER];
+	u8 dqs;
+	u8 mr1_value[FSP_MAX] = { 0x56, 0x56 };
+
+	u32 value_store[MAX_BACKUP_REG_CNT];
+	u32 *regs_backup[] = {
+		&ch[chn].ao.stbcal,
+		&ch[chn].ao.stbcal1,
+		&ch[chn].ao.ddrconf0,
+		&ch[chn].ao.spcmd,
+		&ch[chn].ao.refctrl0,
+		&ch[chn].phy.b[0].dq[6],
+		&ch[chn].phy.b[1].dq[6],
+	};
+	dramc_save_restore_multi_reg(SAVE_VALUE, value_store,
+		regs_backup, ARRAY_SIZE(regs_backup));
+
+	rx_dqs_isi_pulse_cg_switch(chn, DISABLE);
+	dramc_mode_reg_write_by_rank(chn, rank, 0x1, mr1_value[1] | 0x80);
+	clrbits_le32(&ch[chn].ao.refctrl0, 1 << REFCTRL0_PBREFEN_SHIFT);
+
+	dramc_hw_gating_onoff(chn, GATING_OFF);
+
+	setbits_le32(&ch[chn].ao.stbcal1, 1 << STBCAL1_STBENCMPEN_SHIFT);
+	setbits_le32(&ch[chn].ao.stbcal1, 1 << STBCAL1_STBCNT_LATCH_EN_SHIFT);
+	clrbits_le32(&ch[chn].ao.ddrconf0, 1 << DDRCONF0_DM4TO1MODE_SHIFT);
+	setbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_DQSGCNTEN_SHIFT);
+
+	udelay(4);
+	setbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_DQSGCNTRST_SHIFT);
+	udelay(1);
+	clrbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_DQSGCNTRST_SHIFT);
+	clrsetbits_le32(&ch[chn].phy.misc_ctrl1,
+		1 << MISC_CTRL1_R_DMSTBENCMP_RK_OPT_SHIFT,
+		rank << MISC_CTRL1_R_DMSTBENCMP_RK_OPT_SHIFT);
+
+	u32 dummy_rd_backup = read32(&ch[chn].ao.dummy_rd);
+	dramc_engine2_init(chn, rank, 0x23, 1);
+	for (dqs = 0; dqs < DQS_NUMBER; dqs++) {
+		pass_begin[dqs] = 0;
+		pass_count[dqs] = 0;
+		dqs_high[dqs] = 0;
+		dqs_transition[dqs] = 0;
+		dly_coarse_large_cnt[dqs] = 0;
+		dly_coarse_0p5t_cnt[dqs] = 0;
+		dly_fine_tune_cnt[dqs] = 0;
+	}
+
+	dramc_show("[Gating]\n");
+	for (u32 coarse_tune = coarse_start; coarse_tune < coarse_end;
+	     coarse_tune += DQS_GW_COARSE_STEP) {
+		u32 dly_coarse_large_rodt = 0;
+		u32 dly_coarse_0p5t_rodt = 0;
+		u32 dly_coarse_large_rodt_p1 = 4;
+		u32 dly_coarse_0p5t_rodt_p1 = 4;
+
+		u8 dly_coarse_large = coarse_tune / RX_DQS_CTL_LOOP;
+		u8 dly_coarse_0p5t = coarse_tune % RX_DQS_CTL_LOOP;
+		u32 dly_coarse_large_p1 =
+			(coarse_tune + DQS_GW_FREQ_DIV) / RX_DQS_CTL_LOOP;
+		u32 dly_coarse_0p5t_p1 =
+			(coarse_tune + DQS_GW_FREQ_DIV) % RX_DQS_CTL_LOOP;
+		u32 value = (dly_coarse_large << 3) + dly_coarse_0p5t;
+
+		if (value >= 11) {
+			value -= 11;
+			dly_coarse_large_rodt = value >> 3;
+			dly_coarse_0p5t_rodt =
+				value - (dly_coarse_large_rodt << 3);
+
+			value = (dly_coarse_large << 3) + dly_coarse_0p5t - 11;
+			dly_coarse_large_rodt_p1 = value >> 3;
+			dly_coarse_0p5t_rodt_p1 =
+				value - (dly_coarse_large_rodt_p1 << 3);
+		}
+
+		write32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg0,
+			((u32) dly_coarse_large <<
+			SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_SHIFT) |
+			((u32) dly_coarse_large <<
+			SHURK_SELPH_DQSG0_TX_DLY_DQS1_GATED_SHIFT) |
+			(dly_coarse_large_p1 <<
+			SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_SHIFT) |
+			(dly_coarse_large_p1 <<
+			SHURK_SELPH_DQSG0_TX_DLY_DQS1_GATED_P1_SHIFT));
+		write32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg1,
+			((u32) dly_coarse_0p5t <<
+			SHURK_SELPH_DQSG1_REG_DLY_DQS0_GATED_SHIFT) |
+			((u32) dly_coarse_0p5t <<
+			SHURK_SELPH_DQSG1_REG_DLY_DQS1_GATED_SHIFT) |
+			(dly_coarse_0p5t_p1 <<
+			SHURK_SELPH_DQSG1_REG_DLY_DQS0_GATED_P1_SHIFT) |
+			(dly_coarse_0p5t_p1 <<
+			SHURK_SELPH_DQSG1_REG_DLY_DQS1_GATED_P1_SHIFT));
+		write32(&ch[chn].ao.shu[0].rk[rank].selph_odten0,
+			(dly_coarse_large_rodt <<
+			SHURK_SELPH_ODTEN0_TXDLY_B0_RODTEN_SHIFT) |
+			(dly_coarse_large_rodt <<
+			SHURK_SELPH_ODTEN0_TXDLY_B1_RODTEN_SHIFT) |
+			(dly_coarse_large_rodt_p1 <<
+			SHURK_SELPH_ODTEN0_TXDLY_B0_RODTEN_P1_SHIFT) |
+			(dly_coarse_large_rodt_p1 <<
+			SHURK_SELPH_ODTEN0_TXDLY_B1_RODTEN_P1_SHIFT));
+		write32(&ch[chn].ao.shu[0].rk[rank].selph_odten1,
+			(dly_coarse_0p5t_rodt <<
+			SHURK_SELPH_ODTEN1_DLY_B0_RODTEN_SHIFT) |
+			(dly_coarse_0p5t_rodt <<
+			SHURK_SELPH_ODTEN1_DLY_B1_RODTEN_SHIFT) |
+			(dly_coarse_0p5t_rodt_p1 <<
+			SHURK_SELPH_ODTEN1_DLY_B0_RODTEN_P1_SHIFT) |
+			(dly_coarse_0p5t_rodt_p1 <<
+			SHURK_SELPH_ODTEN1_DLY_B1_RODTEN_P1_SHIFT));
+
+		for (u8 dly_fine_xt = DQS_GW_FINE_START;
+			dly_fine_xt < DQS_GW_FINE_END;
+			dly_fine_xt += DQS_GW_FINE_STEP) {
+
+			dramc_set_gating_mode(chn, 0);
+
+			write32(&ch[chn].ao.shu[0].rk[rank].dqsien,
+				dly_fine_xt | (dly_fine_xt << 8));
+
+			dram_phy_reset(chn);
+
+			setbits_le32(&ch[chn].ao.spcmd,
+				1 << SPCMD_DQSGCNTRST_SHIFT);
+			udelay(1);
+			clrbits_le32(&ch[chn].ao.spcmd,
+				1 << SPCMD_DQSGCNTRST_SHIFT);
+
+			dramc_engine2_run(chn, TE_OP_READ_CHECK);
+
+			u32 result_r = read32(&ch[chn].phy.misc_stberr_rk0_r) &
+				    MISC_STBERR_RK_R_STBERR_RK_R_MASK;
+			u32 result_f = read32(&ch[chn].phy.misc_stberr_rk0_f) &
+				    MISC_STBERR_RK_F_STBERR_RK_F_MASK;
+			debug_cnt[0] = read32(&ch[chn].nao.dqsgnwcnt[0]);
+			debug_cnt[1] = (debug_cnt[0] >> 16) & 0xffff;
+			debug_cnt[0] &= 0xffff;
+
+			dramc_set_gating_mode(chn, 1);
+			dramc_engine2_run(chn, TE_OP_READ_CHECK);
+
+			find_dly_tune(chn, dly_coarse_large, dly_coarse_0p5t,
+				dly_fine_xt, dqs_high, dly_coarse_large_cnt,
+				dly_coarse_0p5t_cnt,
+				dly_fine_tune_cnt, dqs_transition);
+
+			dramc_show("%d %d %d |",
+				dly_coarse_large, dly_coarse_0p5t,
+				dly_fine_xt);
+			for (dqs = 0; dqs < DQS_NUMBER; dqs++)
+				dramc_show("%X ", debug_cnt[dqs]);
+
+			dramc_show(" |");
+			for (dqs = 0; dqs < DQS_NUMBER; dqs++) {
+				dramc_show("(%X %X)",
+				(result_f >> (DQS_BIT_NUMBER * dqs)) & 0xff,
+				(result_r >> (DQS_BIT_NUMBER * dqs)) & 0xff);
+			}
+
+			dramc_show("\n");
+			find_gating_window(result_r, result_f, &debug_cnt[0],
+				dly_coarse_large, dly_coarse_0p5t,
+				&pass_begin[0], &pass_count[0],
+				&dly_fine_xt, &coarse_tune, &dqs_high[0]);
+		}
+	}
+
+	dramc_engine2_end(chn);
+	write32(&ch[chn].ao.dummy_rd, dummy_rd_backup);
+
+	for (dqs = 0; dqs < DQS_NUMBER; dqs++) {
+		pass_count[dqs] = dqs_transition[dqs];
+		min_fine_tune[dqs] = dly_fine_tune_cnt[dqs];
+		min_coarse_tune0p5t[dqs] = dly_coarse_0p5t_cnt[dqs];
+		min_coarse_tune2t[dqs] = dly_coarse_large_cnt[dqs];
+
+		u8 tmp_offset = pass_count[dqs] * DQS_GW_FINE_STEP / 2;
+		u8 tmp_value = min_fine_tune[dqs] + tmp_offset;
+		best_fine_tune[dqs] = tmp_value % RX_DLY_DQSIENSTB_LOOP;
+		best_fine_tune_p1[dqs] = best_fine_tune[dqs];
+
+		tmp_offset = tmp_value / RX_DLY_DQSIENSTB_LOOP;
+		tmp_value = min_coarse_tune0p5t[dqs] + tmp_offset;
+		best_coarse_tune0p5t[dqs] = tmp_value % RX_DQS_CTL_LOOP;
+
+		tmp_offset = tmp_value / RX_DQS_CTL_LOOP;
+		best_coarse_tune2t[dqs] =
+			min_coarse_tune2t[dqs] + tmp_offset;
+
+		tmp_value = best_coarse_tune0p5t[dqs] + DQS_GW_FREQ_DIV;
+		best_coarse_tune0p5t_p1[dqs] = tmp_value % RX_DQS_CTL_LOOP;
+
+		tmp_offset = tmp_value / RX_DQS_CTL_LOOP;
+		best_coarse_tune2t_p1[dqs] =
+			best_coarse_tune2t[dqs] + tmp_offset;
+	}
+
+	for (dqs = 0; dqs < DQS_NUMBER; dqs++)
+		dramc_show("best DQS%d dly(2T, 0.5T, fine tune)"
+			" = (%d, %d, %d)\n",
+			dqs, best_coarse_tune2t[dqs],
+			best_coarse_tune0p5t[dqs], best_fine_tune[dqs]);
+
+	for (dqs = 0; dqs < DQS_NUMBER; dqs++)
+		dramc_show("best DQS%d best coarse dly"
+			"(2T, 0.5T, fine tune) = (%d, %d, %d)\n",
+			dqs, best_coarse_tune2t_p1[dqs],
+			best_coarse_tune0p5t_p1[dqs],
+			best_fine_tune[dqs]);
+
+	dramc_save_restore_multi_reg(RESTORE_VALUE, value_store,
+		regs_backup, ARRAY_SIZE(regs_backup));
+
+	dramc_mode_reg_write_by_rank(chn, rank, 0x1, mr1_value[1] & 0x7f);
+	rx_dqs_isi_pulse_cg_switch(chn, ENABLE);
+	write32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg0,
+		((u32) best_coarse_tune2t[0] <<
+		SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_SHIFT) |
+		((u32) best_coarse_tune2t[1] <<
+		SHURK_SELPH_DQSG0_TX_DLY_DQS1_GATED_SHIFT) |
+		((u32) best_coarse_tune2t_p1[0] <<
+		SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_SHIFT) |
+		((u32) best_coarse_tune2t_p1[1] <<
+		SHURK_SELPH_DQSG0_TX_DLY_DQS1_GATED_P1_SHIFT));
+	write32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg1,
+		((u32) best_coarse_tune0p5t[0] <<
+		SHURK_SELPH_DQSG1_REG_DLY_DQS0_GATED_SHIFT) |
+		((u32) best_coarse_tune0p5t[1] <<
+		SHURK_SELPH_DQSG1_REG_DLY_DQS1_GATED_SHIFT) |
+		((u32) best_coarse_tune0p5t_p1[0] <<
+		SHURK_SELPH_DQSG1_REG_DLY_DQS0_GATED_P1_SHIFT) |
+		((u32) best_coarse_tune0p5t_p1[1] <<
+		   SHURK_SELPH_DQSG1_REG_DLY_DQS1_GATED_P1_SHIFT));
+
+	for (dqs = 0; dqs < DQS_NUMBER; dqs++) {
+		u8 tmp_value = (best_coarse_tune2t[dqs] << 3)
+			+ best_coarse_tune0p5t[dqs];
+
+		if (tmp_value >= 11) {
+			tmp_value -= 11;
+			best_coarse_large_rodt[dqs] = tmp_value >> 3;
+			best_coarse_0p5t_rodt[dqs] =
+			    tmp_value - (best_coarse_large_rodt[dqs] << 3);
+
+			tmp_value = (best_coarse_tune2t_p1[dqs] << 3) +
+				best_coarse_tune0p5t_p1[dqs] - 11;
+			best_coarse_large_rodt_p1[dqs] = tmp_value >> 3;
+			best_coarse_0p5t_rodt_p1[dqs] =
+			    tmp_value - (best_coarse_large_rodt_p1[dqs] << 3);
+
+			dramc_dbg("best RODT dly(2T, 0.5T) = (%d, %d)\n",
+				      best_coarse_large_rodt[dqs],
+				      best_coarse_0p5t_rodt[dqs]);
+		} else {
+
+			best_coarse_large_rodt[dqs] = 0;
+			best_coarse_0p5t_rodt[dqs] = 0;
+
+			best_coarse_large_rodt_p1[dqs] = 4;
+			best_coarse_0p5t_rodt_p1[dqs] = 4;
+
+			dramc_dbg("RxdqsGatingCal Error: best_coarse_tune2t:%d"
+			    " is already 0. RODT cannot be -1 coarse tune\n",
+			     dqs);
+		}
+	}
+
+	write32(&ch[chn].ao.shu[0].rk[rank].selph_odten0,
+		((u32) best_coarse_large_rodt[0] <<
+		SHURK_SELPH_ODTEN0_TXDLY_B0_RODTEN_SHIFT) |
+		((u32) best_coarse_large_rodt[1] <<
+		SHURK_SELPH_ODTEN0_TXDLY_B1_RODTEN_SHIFT) |
+		((u32) best_coarse_large_rodt_p1[0] <<
+		SHURK_SELPH_ODTEN0_TXDLY_B0_RODTEN_P1_SHIFT) |
+		((u32) best_coarse_large_rodt_p1[1] <<
+		   SHURK_SELPH_ODTEN0_TXDLY_B1_RODTEN_P1_SHIFT));
+	write32(&ch[chn].ao.shu[0].rk[rank].selph_odten1,
+		((u32) best_coarse_0p5t_rodt[0] <<
+		SHURK_SELPH_ODTEN1_DLY_B0_RODTEN_SHIFT) |
+		((u32) best_coarse_0p5t_rodt[1] <<
+		SHURK_SELPH_ODTEN1_DLY_B1_RODTEN_SHIFT) |
+		((u32) best_coarse_0p5t_rodt_p1[0] <<
+		SHURK_SELPH_ODTEN1_DLY_B0_RODTEN_P1_SHIFT) |
+		((u32) best_coarse_0p5t_rodt_p1[1] <<
+		SHURK_SELPH_ODTEN1_DLY_B1_RODTEN_P1_SHIFT));
+
+	write32(&ch[chn].ao.shu[0].rk[rank].dqsien,
+			best_fine_tune[0] | (best_fine_tune[1] << 8));
+
+	dram_phy_reset(chn);
+}
+
+static void dramc_rx_dqs_gating_post_process(u8 chn)
+{
+	u8 dqs, rank_rx_dvs, dqsinctl, rank;
+	u32 read_dqsinctl, rankinctl_root, xrtr2r, reg_tx_dly_dqsgated_min = 3;
+	u8 txdly_cal_min = 0xff, txdly_cal_max = 0, tx_dly_dqs_gated = 0;
+	u32 best_coarse_tune2t[RANK_MAX][DQS_NUMBER];
+	u32 best_coarse_tune2t_p1[RANK_MAX][DQS_NUMBER];
+
+	rank_rx_dvs = reg_tx_dly_dqsgated_min - 1;
+
+	for (u8 b = 0; b < 2; b++)
+		clrsetbits_le32(&ch[chn].phy.shu[0].b[b].dq[7],
+			SHU1_BX_DQ7_R_DMRANKRXDVS_MASK,
+			rank_rx_dvs << SHU1_BX_DQ7_R_DMRANKRXDVS_SHIFT);
+
+	for (rank = 0; rank < RANK_MAX; rank++) {
+		u32 dqsg0 = read32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg0);
+		for (dqs = 0; dqs < DQS_NUMBER; dqs++) {
+			best_coarse_tune2t[rank][dqs] =
+			   (dqsg0 >> (dqs * 8)) &
+			    SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_MASK;
+			best_coarse_tune2t_p1[rank][dqs] =
+			    ((dqsg0 >> (dqs * 8)) &
+			    SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_MASK) >>
+			    SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_SHIFT;
+			dramc_dbg("rank%d best DQS%d dly(2T, (P1)2T) = (%d, %d)\n",
+			      rank, dqs, best_coarse_tune2t[rank][dqs],
+			      best_coarse_tune2t_p1[rank][dqs]);
+
+			tx_dly_dqs_gated = best_coarse_tune2t[rank][dqs];
+			txdly_cal_min = MIN(txdly_cal_min, tx_dly_dqs_gated);
+
+			tx_dly_dqs_gated = best_coarse_tune2t_p1[rank][dqs];
+			txdly_cal_max = MAX(txdly_cal_max, tx_dly_dqs_gated);
+		}
+	}
+
+	dqsinctl = reg_tx_dly_dqsgated_min - txdly_cal_min;
+	dramc_dbg("dqsinctl:%d, tx_dly_dqsgated_min %d, txdly_cal_min %d\n",
+	     dqsinctl, reg_tx_dly_dqsgated_min, txdly_cal_min);
+
+	if (dqsinctl != 0) {
+		txdly_cal_min += dqsinctl;
+		txdly_cal_max += dqsinctl;
+
+		for (rank = 0; rank < RANK_MAX; rank++) {
+			dramc_dbg("Rank: %d\n", rank);
+			for (dqs = 0; dqs < DQS_NUMBER; dqs++) {
+				best_coarse_tune2t[rank][dqs] += dqsinctl;
+				best_coarse_tune2t_p1[rank][dqs] += dqsinctl;
+
+				dramc_dbg("best DQS%d dly(2T) = (%d)\n",
+					dqs, best_coarse_tune2t[rank][dqs]);
+				dramc_dbg("best DQS%d P1 dly(2T) = (%d)\n",
+					dqs, best_coarse_tune2t_p1[rank][dqs]);
+			}
+
+			write32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg0,
+				(best_coarse_tune2t[rank][0] << 0) |
+				(best_coarse_tune2t[rank][1] << 8) |
+				(best_coarse_tune2t_p1[rank][0] << 4) |
+				(best_coarse_tune2t_p1[rank][1] << 12));
+		}
+	}
+
+	read_dqsinctl = (read32(&ch[chn].ao.shu[0].rk[0].dqsctl) &
+				SHURK_DQSCTL_DQSINCTL_MASK) - dqsinctl;
+	if (read_dqsinctl >= 3) {
+		rankinctl_root = read_dqsinctl - 3;
+	} else {
+		rankinctl_root = 0;
+		dramc_dbg("DQSINCTL < 3, Risk for supporting 1066/RL8\n");
+	}
+
+	clrsetbits_le32(&ch[chn].ao.shu[0].rk[0].dqsctl,
+		SHURK_DQSCTL_DQSINCTL_MASK,
+		read_dqsinctl << SHURK_DQSCTL_DQSINCTL_SHIFT);
+	clrsetbits_le32(&ch[chn].ao.shu[0].rk[1].dqsctl,
+		SHURK_DQSCTL_DQSINCTL_MASK,
+		read_dqsinctl << SHURK_DQSCTL_DQSINCTL_SHIFT);
+	clrsetbits_le32(&ch[chn].ao.shu[0].rankctl,
+		SHU_RANKCTL_RANKINCTL_PHY_MASK |
+		SHU_RANKCTL_RANKINCTL_MASK | SHU_RANKCTL_RANKINCTL_ROOT1_MASK,
+		(read_dqsinctl << SHU_RANKCTL_RANKINCTL_PHY_SHIFT) |
+		(rankinctl_root << SHU_RANKCTL_RANKINCTL_SHIFT) |
+		(rankinctl_root << SHU_RANKCTL_RANKINCTL_ROOT1_SHIFT));
+
+	xrtr2r = MIN(8 + txdly_cal_max + 1, 12);
+	clrsetbits_le32(&ch[chn].ao.shu[0].actim_xrt,
+		SHU_ACTIM_XRT_XRTR2R_MASK,
+		xrtr2r << SHU_ACTIM_XRT_XRTR2R_SHIFT);
+
+	dramc_dbg("TX_dly_DQS gated check: min %d max %d, ChangeDQSINCTL=%d\n"
+		"DQSINCTL=%d, RANKINCTL=%d, XRTR2R=%d\n",
+		txdly_cal_min, txdly_cal_max, dqsinctl,
+		read_dqsinctl, rankinctl_root, xrtr2r);
+}
+
 void dramc_calibrate_all_channels(const struct sdram_params *pams)
 {
 	for (u8 chn = 0; chn < CHANNEL_MAX; chn++) {
@@ -319,6 +970,9 @@
 			cmd_bus_training(chn, rk, pams);
 			dramc_write_leveling(chn, rk, pams->wr_level);
 			auto_refresh_switch(chn, 1);
+			dramc_rx_dqs_gating_cal(chn, rk);
 		}
+
+		dramc_rx_dqs_gating_post_process(chn);
 	}
 }
diff --git a/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h b/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h
index f5b6251..761fff6 100644
--- a/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h
+++ b/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h
@@ -140,4 +140,6 @@
 void dramc_sw_impedance(const struct sdram_params *params);
 void dramc_apply_pre_calibration_config(void);
 void dramc_calibrate_all_channels(const struct sdram_params *params);
+void dramc_save_restore_multi_reg(u8 type, u32 *store_mem,
+		u32 **addr, u32 count);
 #endif /* _DRAMC_PI_API_MT8183_H */

-- 
To view, visit https://review.coreboot.org/28841
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I504d6d5c9ea01b11a9f2a05b5ee4b5f1af87e23f
Gerrit-Change-Number: 28841
Gerrit-PatchSet: 1
Gerrit-Owner: Tristan Hsieh <tristan.shieh at mediatek.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20181001/5b24fca3/attachment-0001.html>


More information about the coreboot-gerrit mailing list