Tristan Hsieh has uploaded this change for review. ( https://review.coreboot.org/28437
Change subject: mediatek/mt8183: Add MediaTek DDR driver ......................................................................
mediatek/mt8183: Add MediaTek DDR driver
Add DDR driver to initialize memory.
BUG=b:80501386 BRANCH=none TEST=Boots correctly on Kukui, and inits DRAM successfully with related patches.
Change-Id: Iaaa1db170c168a58b020095ae45d98355d8dfcb0 Signed-off-by: Junzhi Zhao junzhi.zhao@mediatek.com --- M src/soc/mediatek/mt8183/Kconfig M src/soc/mediatek/mt8183/Makefile.inc A src/soc/mediatek/mt8183/dramc_pi_basic_api.c A src/soc/mediatek/mt8183/dramc_pi_calibration_api.c M src/soc/mediatek/mt8183/emi.c M src/soc/mediatek/mt8183/include/soc/addressmap.h A src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h A src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h A src/soc/mediatek/mt8183/include/soc/dramc_register.h M src/soc/mediatek/mt8183/include/soc/emi.h M src/soc/mediatek/mt8183/include/soc/memlayout.ld A src/soc/mediatek/mt8183/memory.c M src/soc/mediatek/mt8183/pll.c 13 files changed, 6,648 insertions(+), 5 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/37/28437/1
diff --git a/src/soc/mediatek/mt8183/Kconfig b/src/soc/mediatek/mt8183/Kconfig index b58be7f..1c78b18 100644 --- a/src/soc/mediatek/mt8183/Kconfig +++ b/src/soc/mediatek/mt8183/Kconfig @@ -19,4 +19,14 @@ select VBOOT_STARTS_IN_BOOTBLOCK select VBOOT_SEPARATE_VERSTAGE
+config DEBUG_DRAM + bool "Output verbose DRAM related debug message" + default n + help + This option enables additional DRAM related debug messages. + +config MEMORY_TEST + bool + default y + endif diff --git a/src/soc/mediatek/mt8183/Makefile.inc b/src/soc/mediatek/mt8183/Makefile.inc index 8fece79..2c128f9 100644 --- a/src/soc/mediatek/mt8183/Makefile.inc +++ b/src/soc/mediatek/mt8183/Makefile.inc @@ -21,6 +21,10 @@ verstage-y += ../common/wdt.c
romstage-y += ../common/cbmem.c emi.c +romstage-y += dramc_pi_basic_api.c +romstage-y += dramc_pi_calibration_api.c +romstage-y += memory.c +romstage-$(CONFIG_MEMORY_TEST) += ../common/memory_test.c romstage-y += ../common/gpio.c gpio.c romstage-y += ../common/mmu_operations.c mmu_operations.c romstage-$(CONFIG_SPI_FLASH) += ../common/spi.c spi.c diff --git a/src/soc/mediatek/mt8183/dramc_pi_basic_api.c b/src/soc/mediatek/mt8183/dramc_pi_basic_api.c new file mode 100644 index 0000000..6619540 --- /dev/null +++ b/src/soc/mediatek/mt8183/dramc_pi_basic_api.c @@ -0,0 +1,1852 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/io.h> +#include <delay.h> +#include <soc/infracfg.h> +#include <soc/spm.h> +#include <soc/pll.h> +#include <soc/dramc_register.h> +#include <soc/dramc_pi_api.h> +#include <soc/emi.h> + +void dramc_broadcast_onoff(u32 bOnOff) +{ + write32(&mt8183_infracfg->dramc_wbr, bOnOff); +} + +u32 get_dramc_broadcast(void) +{ + return read32(&mt8183_infracfg->dramc_wbr); +} + +static void transfer_pll_to_spm_control(void) +{ + u8 shu_level; + shu_level = read32(&ch[0].ao.shustatus); + shu_level = (shu_level & 0x00000006) >> 1; + + /* set SPM project code and enable clock enable */ + clrsetbits_le32(&mtk_spm->poweron_config_set, + (0xffff << 16) | (0x1 << 0), + (0xb16 << 16) | (0x1 << 0)); + + /* set SPM pinmux */ + clrbits_le32(&mtk_spm->pcm_pwr_io_en, (0xff << 0) | (0xff << 16)); + setbits_le32(&mtk_spm->dramc_dpy_clk_sw_con_sel, + 0xffffffff << 0); + setbits_le32(&mtk_spm->dramc_dpy_clk_sw_con_sel2, + 0xffffffff << 0); + + setbits_le32(&mtk_spm->spm_power_on_val0, + (0x1 << 8) | (0xf << 12)); + setbits_le32(&mtk_spm->spm_s1_mode_ch, (0x3 << 0)); + + shu_level = (shu_level == 1) ? 2 : 1; + clrsetbits_le32(&mtk_spm->spm_power_on_val0, + (0x3 << 28), (shu_level << 28)); + clrsetbits_le32(&mtk_spm->dramc_dpy_clk_sw_con2, + (0x3 << 2), (shu_level << 2)); + + udelay(1); + for (u8 chn = CHANNEL_A; chn < CHANNEL_NUM; chn++) { + clrbits_le32(&ch[chn].phy.pll1, (0x1 << 31)); + clrbits_le32(&ch[chn].phy.pll2, (0x1 << 31)); + } +} + +static void dramc_hw_dqs_gating_tracking(u8 chn) +{ + setbits_le32(&ch[chn].ao.stbcal, + (0x3 << 26) | (0x1 << 0)); + clrsetbits_le32(&ch[chn].ao.stbcal1, + (0xffff << 16) | (0x1 << 8) | (0x1 << 6), + (0x1 << 16) | (0x1 << 8) | (0x0 << 6)); + + clrsetbits_le32(&ch[chn].phy.misc_ctrl0, + (0x1 << 24) | (0x1f << 11) | (0xf << 0), + (0x1 << 24) | (0x0 << 11) | (0x0 << 0)); + + clrbits_le32(&ch[chn].phy.b[0].dq[6], (0x1 << 31)); + clrbits_le32(&ch[chn].phy.b[1].dq[6], (0x1 << 31)); + clrbits_le32(&ch[chn].phy.ca_cmd[6], (0x1 << 31)); +} + +static void dramc_hw_gating_init(void) +{ + for (u8 chn = 0; chn < CHANNEL_NUM; chn++) { + clrbits_le32(&ch[chn].ao.stbcal, + (0x7 << 22) | (0x3 << 14) | (0x1 << 19) | (0x1 << 21)); + setbits_le32(&ch[chn].ao.stbcal, + (0x1 << 20) | (0x3 << 28)); + setbits_le32(&ch[chn].phy.misc_ctrl1, (0x1 << 24)); + + dramc_hw_dqs_gating_tracking(chn); + } +} + +static void dramc_rx_input_delay_tracking_init(u8 chn) +{ + /* Enable RX_FIFO macro DIV4 clock CG */ + write32(&ch[chn].phy.misc_cg_ctrl1, 0xffffffff); + + /* DVS mode to RG mode */ + clrbits_le32(&ch[chn].phy.r[0].b[0].rxdvs[2], (0x3 << 30)); + clrbits_le32(&ch[chn].phy.r[0].b[1].rxdvs[2], (0x3 << 30)); + clrbits_le32(&ch[chn].phy.r[1].b[0].rxdvs[2], (0x3 << 30)); + clrbits_le32(&ch[chn].phy.r[1].b[1].rxdvs[2], (0x3 << 30)); + + clrbits_le32(&ch[chn].phy.b0_rxdvs[0], (0x1 << 19)); + clrbits_le32(&ch[chn].phy.b1_rxdvs[0], (0x1 << 19)); + setbits_le32(&ch[chn].phy.b0_rxdvs[0], (0x1 << 9)); + setbits_le32(&ch[chn].phy.b1_rxdvs[0], (0x1 << 9)); + + for (size_t b = 0; b < 2; b++) { + /* tracking rising and update rising/falling together */ + clrbits_le32(&ch[chn].phy.r[0].b[b].rxdvs[2], (0x1 << 29)); + clrbits_le32(&ch[chn].phy.r[1].b[b].rxdvs[2], (0x1 << 29)); + + /* DQS, DQ, DQM (DQ, DQM are tied together now) + * -> controlled using DQM MAX_MIN */ + clrsetbits_le32(&ch[chn].phy.r[0].b[b].rxdvs[7], + (0x3f << 0) | (0x3f << 8) | (0x7f << 16) | (0x7f << 24), + (0x0 << 0) | (0x3f << 8) | (0x0 << 16) | (0x7f << 24)); + clrsetbits_le32(&ch[chn].phy.r[0].b[b].rxdvs[1], + (0xffff << 16) | (0xffff << 0), + (0x2 << 16) | (0x2 << 0)); + + /* DQ/DQS Rx DLY adjustment for tracking mode */ + clrbits_le32(&ch[chn].phy.r[0].b[b].rxdvs[2], + (0x3 << 26) | (0x3 << 24) | (0x3 << 18) | (0x3 << 16)); + + /* DQS, DQ, DQM (DQ, DQM are tied together now) + * -> controlled using DQM MAX_MIN */ + clrsetbits_le32(&ch[chn].phy.r[1].b[b].rxdvs[7], + (0x3f << 0) | (0x3f << 8) | (0x7f << 16) | (0x7f << 24), + (0x0 << 0) | (0x3f << 8) | (0x0 << 16) | (0x7f << 24)); + clrsetbits_le32(&ch[chn].phy.r[1].b[b].rxdvs[1], + (0xffff << 16) | (0xffff << 0), + (0x2 << 16) | (0x2 << 0)); + + /* DQ/DQS Rx DLY adjustment for tracking mode */ + clrbits_le32(&ch[chn].phy.r[1].b[b].rxdvs[2], + (0x3 << 26) | (0x3 << 24)); + clrbits_le32(&ch[chn].phy.r[1].b[b].rxdvs[2], + (0x3 << 18) | (0x3 << 16)); + } +} + +static void dramc_rx_input_delay_tracking(u8 chn) +{ + clrbits_le32(&ch[chn].phy.ca_cmd[10], + (0x7 << 28) | (0x7 << 24)); + + /* Rx DLY tracking setting (Static) */ + clrsetbits_le32(&ch[chn].phy.b0_rxdvs[0], + (0x1 << 29) | (0xf << 4) | (0x1 << 0), + (0x1 << 29) | (0x0 << 4) | (0x1 << 0)); + clrsetbits_le32(&ch[chn].phy.b1_rxdvs[0], + (0x1 << 29) | (0xf << 4) | (0x1 << 0), + (0x1 << 29) | (0x0 << 4) | (0x1 << 0)); + + for (u8 b = 0; b < 2; b++) { + clrsetbits_le32(&ch[chn].phy.b[b].dq[9], + (0x7 << 28) | (0x7 << 24), + (0x1 << 28) | (0x0 << 24)); + setbits_le32(&ch[chn].phy.b[b].dq[5], (0x1 << 31)); + } + + setbits_le32(&ch[chn].phy.b0_rxdvs[0], (0x1 << 28) | (0x1 << 31)); + setbits_le32(&ch[chn].phy.b1_rxdvs[0], (0x1 << 28) | (0x1 << 31)); + + for (u8 rank = RANK_0; rank < RANK_MAX; rank++) { + /* Rx DLY tracking update enable (HW mode) */ + clrsetbits_le32(&ch[chn].phy.r[rank].b[0].rxdvs[2], + (0x3 << 30) | (0x1 << 28) | (0x1 << 23), + (0x2 << 30) | (0x1 << 28) | (0x1 << 23)); + + clrsetbits_le32(&ch[chn].phy.r[rank].b[1].rxdvs[2], + (0x3 << 30) | (0x1 << 28) | (0x1 << 23), + (0x2 << 30) | (0x1 << 28) | (0x1 << 23)); + } +} + +static void dramc_impedance_tracking_enable(void) +{ + u8 chn; + + setbits_le32(&ch[0].phy.misc_ctrl0, (0x1 << 10)); + for (chn = 0; chn < CHANNEL_NUM; chn++) { + setbits_le32(&ch[chn].ao.impcal, (0x1 << 31) | (0x1 << 29) | + (0x1 << 26) | (0x1 << 17) | (0x7 << 11)); + clrbits_le32(&ch[chn].ao.impcal, (0x1 << 30)); + setbits_le32(&ch[chn].phy.misc_ctrl0, (0x1 << 18)); + setbits_le32(&ch[chn].ao.impcal, (0x1 << 19)); + } + setbits_le32(&ch[0].ao.impcal, (0x1 << 14)); + setbits_le32(&ch[1].ao.refctrl0, (0x1 << 2)); + for (chn = 0; chn < CHANNEL_NUM; chn++) + setbits_le32(&ch[chn].ao.refctrl0, (0x1 << 3)); +} + +void dramc_runtime_config(void) +{ + u8 chn = 0, shu = 0, shuCnt = DRAM_DFS_SHUFFLE_MAX; + + clrbits_le32(&ch[0].ao.refctrl0, (0x1 << 29)); + clrbits_le32(&ch[1].ao.refctrl0, (0x1 << 29)); + + transfer_pll_to_spm_control(); + + setbits_le32(&mtk_spm->spm_power_on_val0, (0x3 << 25)); + + dramc_dbg("TX_TRACKING: OFF\n"); + for (chn = 0; chn < CHANNEL_NUM; chn++) { + dramc_rx_input_delay_tracking_init(chn); + dramc_rx_input_delay_tracking(chn); + } + dramc_dbg("RX_TRACKING: ON\n"); + + dramc_hw_gating_init(); + dramc_hw_gating_onoff(CHANNEL_A, GATING_ON); + dramc_dbg("HW_GATING: ON\n"); + + for (chn = 0; chn < CHANNEL_NUM; chn++) { + clrbits_le32(&ch[chn].ao.stbcal2, + (0x3 << 4) | (0x3 << 8) | (0x1 << 28)); + } + dramc_dbg("HW_GATING DBG: OFF\n"); + + /* ZQCS_ENABLE_LP4 */ + clrbits_le32(&ch[0].ao.spcmdctrl, (0x1 << 30)); + clrbits_le32(&ch[1].ao.spcmdctrl, (0x1 << 30)); + dramc_dbg("ZQCS_ENABLE_LP4: OFF\n"); + + enable_dramc_phy_dcm(0); + dramc_dbg("LOWPOWER_GOLDEN_SETTINGS(DCM): OFF\n"); + + for (chn = 0; chn < CHANNEL_NUM; chn++) { + for (shu = 0; shu < shuCnt; shu++) + clrbits_le32(&ch[chn].ao.shu[shu].dqsg_retry, + (0x1 << 1) | (0x3 << 13)); + } + dramc_dbg("DUMMY_READ_FOR_DQS_GATING_RETRY: OFF\n"); + + write32(&ch[0].phy.misc_spm_ctrl0, 0xfbffefff); + write32(&ch[1].phy.misc_spm_ctrl0, 0xfbffefff); + write32(&ch[0].phy.misc_spm_ctrl2, 0xffffffef); + write32(&ch[1].phy.misc_spm_ctrl2, 0x7fffffef); + dramc_dbg("SPM_CONTROL_AFTERK: ON\n"); + + dramc_impedance_tracking_enable(); + dramc_dbg("IMPEDANCE_TRACKING: ON\n"); + + for (chn = 0; chn < CHANNEL_NUM; chn++) { + clrbits_le32(&ch[chn].ao.spcmdctrl, (0x3 << 28)); + setbits_le32(&ch[chn].ao.hw_mrr_fun, + (0x1 << 0) | (0x1 << 11)); + dramc_dbg("TEMP_SENSOR: ON\n"); + + + clrbits_le32(&ch[0].ao.refctrl0, (0x1 << 18)); + dramc_dbg("PER_BANK_REFRESH: OFF\n"); + + setbits_le32(&ch[chn].phy.dvfs_emi_clk, (0x1 << 24)); + setbits_le32(&ch[chn].ao.dvfsdll, (0x1 << 7)); + } +} + +void cke_fix_onoff(int option, u8 chn) +{ + u8 on, off; + + /* if CKE is dynamic, set both CKE fix On and Off as 0 */ + if (option == CKE_DYNAMIC) { + /* After CKE FIX on/off, + * CKE should be returned to dynamic (control by HW) */ + on = off = 0; + } else { + /* if CKE fix on is set as 1, + * CKE fix off should also be set as 0; vice versa */ + on = option; + off = (1 - option); + } + + clrsetbits_le32(&ch[chn].ao.ckectrl, + (0x1 << 6) | (0x1 << 7), (on << 6) | (off << 7)); +} + +static void auto_refresh_cke_off(void) +{ + u8 chn; + u32 broadcast_bak = get_dramc_broadcast(); + dramc_broadcast_onoff(DRAMC_BROADCAST_OFF); + + for (chn = 0; chn < CHANNEL_NUM; chn++) + setbits_le32(&ch[chn].ao.refctrl0, (0x1 << 29)); + + udelay(3); + cke_fix_onoff(CKE_FIXOFF, CHANNEL_A); + cke_fix_onoff(CKE_FIXOFF, CHANNEL_B); + + dramc_broadcast_onoff(broadcast_bak); +} + +static void dramc_set_rank_engine2(u8 chn, u8 u1RankSel) +{ + setbits_le32(&ch[chn].ao.dramctrl, + 0x1 << DRAMCTRL_ADRDECEN_TARKMODE_SHIFT); + clrbits_le32(&ch[chn].ao.test2_4, TEST2_4_TESTAGENTRKSEL_MASK); + clrsetbits_le32(&ch[chn].ao.test2_4, TEST2_4_TESTAGENTRK_MASK, + (u1RankSel << TEST2_4_TESTAGENTRK_SHIFT)); +} + +static void save_restore_dummyrd(u8 chn, u8 type) +{ + static u32 uiReg0D0h = 0; + + if (type == SAVE_VALUE) + uiReg0D0h = read32(&ch[chn].ao.dummy_rd); + else + write32(&ch[chn].ao.dummy_rd, uiReg0D0h); +} + +void save_restore_multi_reg(u8 type, u32 **reg_addr, u32 reg_count) +{ + static u32 u4gpRegBackupVlaue[MAX_BACKUP_REG_CNT]; + if (reg_count > MAX_BACKUP_REG_CNT) { + dramc_dbg("save restore count over %d\n", MAX_BACKUP_REG_CNT); + return; + } + + if (type == SAVE_VALUE) { + for (int i = 0; i < reg_count; i++) + u4gpRegBackupVlaue[i] = read32(reg_addr[i]); + } else { + for (int i = 0; i < reg_count; i++) + write32(reg_addr[i], u4gpRegBackupVlaue[i]); + } +} + +void dramc_engine2_init(u8 chn, u8 u1RankSel, u32 test2_1, u32 test2_2, + u8 testaudpat, u8 log2loopcount) +{ + dramc_set_rank_engine2(chn, u1RankSel); + + save_restore_dummyrd(chn, SAVE_VALUE); + 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); + + clrbits_le32(&ch[chn].ao.test2_3, + (0x1 << TEST2_3_TEST2W_SHIFT) | + (0x1 << TEST2_3_TEST2R_SHIFT) | + (0x1 << TEST2_3_TEST1_SHIFT)); + clrsetbits_le32(&ch[chn].ao.test2_0, + TEST2_0_PAT0_MASK | TEST2_0_PAT1_MASK, + (((test2_1 >> 24) & 0xff) << TEST2_0_PAT0_SHIFT) | + (((test2_2 >> 24) & 0xff) << TEST2_0_PAT1_SHIFT)); + + write32(&ch[chn].ao.test2_1, (test2_1 << 4) & 0x00ffffff); + write32(&ch[chn].ao.test2_2, (test2_2 << 4) & 0x00ffffff); + + if (testaudpat == TEST_XTALK_PATTERN) { + clrsetbits_le32(&ch[chn].ao.test2_4, + 0x1 << TEST2_4_TEST_REQ_LEN1_SHIFT | + (0x1 << TEST2_4_TESTAUDMODE_SHIFT) | + (0x1 << TEST2_4_TESTAUDBITINV_SHIFT) | + (0x1 << TEST2_4_TESTSSOPAT_SHIFT) | + (0x1 << TEST2_4_TESTSSOXTALKPAT_SHIFT), + 0x1 << TEST2_4_TESTXTALKPAT_SHIFT); + setbits_le32(&ch[chn].ao.perfctl0, + 0x1 << PERFCTL0_RWOFOEN_SHIFT); + clrsetbits_le32(&ch[chn].ao.test2_3, + (0x1 << TEST2_3_TESTAUDPAT_SHIFT) | + TEST2_3_TESTCNT_MASK, + log2loopcount << TEST2_3_TESTCNT_SHIFT); + } else if (testaudpat == TEST_AUDIO_PATTERN) { + clrsetbits_le32(&ch[chn].ao.test2_4, + TEST2_4_TESTAUDINIT_MASK | + TEST2_4_TESTAUDINC_MASK | + (0x1 << TEST2_4_TESTXTALKPAT_SHIFT), + (0x00000011 << TEST2_4_TESTAUDINIT_SHIFT) | + (0x0000000d << TEST2_4_TESTAUDINC_SHIFT) | + (0x1 << TEST2_4_TESTAUDMODE_SHIFT) | + (0x1 << TEST2_4_TESTAUDBITINV_SHIFT)); + clrsetbits_le32(&ch[chn].ao.test2_3, TEST2_3_TESTCNT_MASK, + (0x1 << TEST2_3_TESTAUDPAT_SHIFT) | + (log2loopcount << TEST2_3_TESTCNT_SHIFT)); + } else { + clrsetbits_le32(&ch[chn].ao.test2_3, + (0x1 << TEST2_3_TESTAUDPAT_SHIFT) | + TEST2_3_TESTCNT_MASK, + (log2loopcount << TEST2_3_TESTCNT_SHIFT)); + clrbits_le32(&ch[chn].ao.test2_4, + (0x1 << TEST2_4_TESTXTALKPAT_SHIFT)); + } +} + +static void dramc_engine2_check_complete(u8 chn) +{ + u32 u4loop_count = 0; + while ((read32(&ch[chn].nao.testrpt) & + (0x1 << TESTRPT_DM_CMP_CPT_RK0_SHIFT)) == 0) { + udelay(1); + u4loop_count++; + + if (u4loop_count > MAX_CMP_CPT_WAIT_LOOP) { + dramc_dbg("MEASURE_A timeout\n"); + break; + } + } + +} + +u32 dramc_engine2_run(u8 chn, enum dram_te_op wr, u8 testaudpat) +{ + u32 u4result = 0xffffffff; + + if (wr == TE_OP_READ_CHECK) { + if ((testaudpat == TEST_AUDIO_PATTERN) || + (testaudpat == TEST_XTALK_PATTERN)) + 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; +} + +void dramc_engine2_end(u8 chn) +{ + clrbits_le32(&ch[chn].ao.test2_4, (0x1 << 17)); + + save_restore_dummyrd(chn, RESTORE_VALUE); +} + +static void ddr_phy_pll_setting(u8 chn) +{ + u8 u1CAP_SEL; + u8 u1MID_FINE_TUNE_SEL; + u8 u1VTH_SEL; + + u1VTH_SEL = 0x2; + u1CAP_SEL = 0x0; + u1MID_FINE_TUNE_SEL = 0x2; + + clrbits_le32(&ch[chn].phy.shu[0].pll[4], 0xFFFF); + clrbits_le32(&ch[chn].phy.shu[0].pll[6], 0xFFFF); + + if (chn == 0) + setbits_le32(&ch[chn].phy.misc_shu_opt, 0x1 << 18); + else if (chn == 1) + setbits_le32(&ch[chn].phy.misc_shu_opt, 0x2 << 18); + + clrsetbits_le32(&ch[chn].phy.ckmux_sel, + 0x3 << 18 | 0x3 << 16, 0x0); + clrsetbits_le32(&ch[chn].phy.shu[0].ca_cmd[0], + 0x3 << 18, 0x1 << 18); + + clrsetbits_le32(&ch[chn].ao.dvfsdll, 0x1 << 1, 0x0 << 1); + + if (chn == DLL_MASTER_CH) { + clrsetbits_le32(&ch[chn].phy.shu[0].ca_dll[0], + 0x1 << 31 | 0x1 << 30 | 0xf << 20 | 0xf << 16 | + 0xf << 12 | 0x1 << 10 | 0x1 << 9 | 0x1 << 4, + 0x0 << 31 | 0x0 << 30 | 0x6 << 20 | 0x9 << 16 | + 0x8 << 12 | 0x1 << 10 | 0x1 << 9 | 0x1 << 4); + clrsetbits_le32(&ch[chn].phy.shu[0].ca_dll[1], + 0x1 << 2 | 0x1 << 0, 0x1 << 2 | 0x0 << 0); + clrsetbits_le32(&ch[chn].phy.shu[0].ca_cmd[6], + 0x1 << 7, 0x1 << 7); + } else { + clrsetbits_le32(&ch[chn].phy.shu[0].ca_dll[0], + 0x1 << 31 | 0x1 << 30 | 0xf << 20 | 0xf << 16 | + 0xf << 12 | 0x1 << 10 | 0x1 << 9 | 0x1 << 4, + 0x1 << 31 | 0x1 << 30 | 0x7 << 20 | 0x7 << 16 | + 0x8 << 12 | 0x1 << 10 | 0x1 << 9 | 0x0 << 4); + clrsetbits_le32(&ch[chn].phy.shu[0].ca_dll[1], + 0x1 << 2 | 0x1 << 0, 0x0 << 2 | 0x1 << 0); + clrsetbits_le32(&ch[chn].phy.shu[0].ca_cmd[6], + 0x1 << 7, 0x0 << 7); + } + + u32 *u4RegBackup[] = { + &ch[chn].phy.b[0].dq[7], + &ch[chn].phy.b[1].dq[7], + &ch[chn].phy.ca_cmd[7], + }; + + save_restore_multi_reg(SAVE_VALUE, + u4RegBackup, ARRAY_SIZE(u4RegBackup)); + + for (size_t b = 0; b < 2; b++) { + setbits_le32(&ch[chn].phy.b[b].dq[7], + 0x1 << 6 | 0x1 << 4 | 0x1 << 2 | 0x1 << 0); + } + setbits_le32(&ch[chn].phy.ca_cmd[7], + 0x1 << 6 | 0x1 << 4 | 0x1 << 2 | 0x1 << 0); + setbits_le32(&ch[chn].phy.ca_cmd[2], 0x1 << 21); + + /* 26M */ + clrsetbits_le32(&ch[chn].phy.misc_cg_ctrl0, (0x3<<4), 0x0 << 4); + + /* MID FINE_TUNE */ + clrbits_le32(&ch[chn].phy.shu[0].b[0].dq[6], (0x1<<26)|(0x1<<27)); + clrbits_le32(&ch[chn].phy.shu[0].b[1].dq[6], (0x1<<26)|(0x1<<27)); + clrbits_le32(&ch[chn].phy.shu[0].ca_cmd[6], (0x1<<26)|(0x1<<27)); + clrbits_le32(&ch[chn].phy.pll4, (0x1<<16)|(0x1<<22)); + + /* PLL */ + clrbits_le32(&ch[chn].phy.pll1, (0x1<<31)); + clrbits_le32(&ch[chn].phy.pll2, (0x1<<31)); + + /* DLL */ + clrbits_le32(&ch[chn].phy.ca_dll_fine_tune[2], (0x0<<0)); + clrbits_le32(&ch[chn].phy.b[0].dll_fine_tune[2], (0x0<<0)); + clrbits_le32(&ch[chn].phy.b[1].dll_fine_tune[2], (0x0<<0)); + setbits_le32(&ch[chn].phy.b[0].dll_fine_tune[2], + (0x1<<10) | (0x1<<11) | (0x1<<13) | (0x1<<14) | (0x1<<15) | + (0x1<<17) | (0x1<<19) | (0x1<<27) | (0x1<<31)); + setbits_le32(&ch[chn].phy.b[1].dll_fine_tune[2], + (0x1<<10) | (0x1<<11) | (0x1<<13) | (0x1<<14) | (0x1<<15) | + (0x1<<17) | (0x1<<19) | (0x1<<27) | (0x1<<31)); + setbits_le32(&ch[chn].phy.ca_dll_fine_tune[2], + (0x1<<10) | (0x1<<11) | (0x1<<13) | (0x1<<15) | (0x1<<16) | + (0x1<<17) | (0x1<<19) | (0x1<<27) | (0x1<<31)); + + /* RESETB */ + clrbits_le32(&ch[chn].phy.ca_dll_fine_tune[0], (0x1<<3)); + clrbits_le32(&ch[chn].phy.b[0].dll_fine_tune[0], (0x1<<3)); + clrbits_le32(&ch[chn].phy.b[1].dll_fine_tune[0], (0x1<<3)); + + udelay(1); + + /* MPLL 52M */ + clrsetbits_le32(&ch[chn].phy.shu[0].pll[8], + (0x7<<0)|(0x3<<18), (0x0<<0)|(0x1<<18)); + clrsetbits_le32(&ch[chn].phy.shu[0].pll[10], + (0x7<<0)|(0x3<<18), (0x0<<0)|(0x1<<18)); + clrsetbits_le32(&ch[chn].phy.shu[0].pll[5], + (0xffff<<16) | 0x1 << 0, (0x7b00<<16)); + clrsetbits_le32(&ch[chn].phy.shu[0].pll[7], + (0xffff<<16) | 0x1 << 0, (0x7b00<<16)); + + setbits_le32(&ch[chn].phy.ca_dll_fine_tune[0], (0x1<<1)); + setbits_le32(&ch[chn].phy.b[0].dll_fine_tune[0], (0x1<<1)); + setbits_le32(&ch[chn].phy.b[1].dll_fine_tune[0], (0x1<<1)); + + clrbits_le32(&ch[chn].phy.ca_dll_fine_tune[1], (0x1<<11)); + clrbits_le32(&ch[chn].phy.b[0].dll_fine_tune[1], (0x1<<19)); + clrbits_le32(&ch[chn].phy.b[1].dll_fine_tune[1], (0x1<<19)); + + clrsetbits_le32(&ch[chn].phy.shu[0].b[0].dq[6], + (0x3<<22) | (0x3<<24) | (0x3<<28), + (u1MID_FINE_TUNE_SEL<<22) | (u1VTH_SEL<<24) | (u1CAP_SEL<<28)); + clrsetbits_le32(&ch[chn].phy.shu[0].b[1].dq[6], + (0x3<<22) | (0x3<<24) | (0x3<<28), + (u1MID_FINE_TUNE_SEL<<22)|(u1VTH_SEL<<24) | (u1CAP_SEL<<28)); + clrsetbits_le32(&ch[chn].phy.shu[0].ca_cmd[6], + (0x3<<22) | (0x3<<24) | (0x3<<28), + (u1MID_FINE_TUNE_SEL<<22) | (u1VTH_SEL<<24) | (u1CAP_SEL<<28)); + + /* RESETB */ + setbits_le32(&ch[chn].phy.ca_dll_fine_tune[0], (0x1<<3)); + setbits_le32(&ch[chn].phy.b[0].dll_fine_tune[0], (0x1<<3)); + setbits_le32(&ch[chn].phy.b[1].dll_fine_tune[0], (0x1<<3)); + udelay(1); + + /* PLL EN */ + setbits_le32(&ch[chn].phy.pll1, (0x1<<31)); + setbits_le32(&ch[chn].phy.pll2, (0x1<<31)); + udelay(100); + + /* MID FINE_TUNE Init 1 */ + setbits_le32(&ch[chn].phy.pll4, (0x1<<16)|(0x1<<22)); + udelay(1); + + /* MID FINE_TUNE Init 2 */ + clrsetbits_le32(&ch[chn].phy.shu[0].b[0].dq[6], + (0x1<<26) | (0x1<<27), (0x1<<26) | (0x0<<27)); + clrsetbits_le32(&ch[chn].phy.shu[0].b[1].dq[6], + (0x1<<26) | (0x1<<27), (0x1<<26) | (0x0<<27)); + clrsetbits_le32(&ch[chn].phy.shu[0].ca_cmd[6], + (0x1<<26) | (0x1<<27), (0x1<<26) | (0x0<<27)); + udelay(1); + if (chn == 0) + clrsetbits_le32(&ch[chn].phy.ca_dll_fine_tune[3], + (0x1<<13) | (0x1<<15) | (0x1<<16) | + (0x1<<17) | (0x1<<19), + (0x1<<13) | (0x1<<15) | (0x1<<16) | + (0x1<<17) | (0x1<<19)); + else if (chn == 1) + clrsetbits_le32(&ch[chn].phy.ca_dll_fine_tune[3], + (0x1<<13) | (0x1<<15) | (0x1<<16) | + (0x1<<17) | (0x1<<19), + (0x1<<13) | (0x1<<15) | (0x1<<16) | (0x1<<17)); + + setbits_le32(&ch[chn].phy.b[0].dll_fine_tune[3], + (0x1<<11) | (0x1<<13) | (0x1<<14) | (0x1<<15) | (0x1<<17)); + setbits_le32(&ch[chn].phy.b[1].dll_fine_tune[3], + (0x1<<11) | (0x1<<13) | (0x1<<14) | (0x1<<15) | (0x1<<17)); + + clrbits_le32(&ch[chn].phy.ca_dll_fine_tune[2], + (0x1 << 10) | (0x1 << 13) | + (0x1 << 15) | (0x1 << 16) | (0x1 << 17) | + (0x1 << 19) | (0x1 << 27) | (0x1 << 31)); + + clrbits_le32(&ch[chn].phy.b[0].dll_fine_tune[2], + (0x1 << 10) | (0x1 << 13) | (0x1 << 14) | + (0x1 << 15) | (0x1 << 17) | + (0x1 << 19) | (0x1 << 27) | (0x1 << 31)); + clrbits_le32(&ch[chn].phy.b[1].dll_fine_tune[2], + (0x1 << 10) | (0x1 << 13) | + (0x1 << 14) | (0x1 << 15) | (0x1 << 17) | + (0x1 << 19) | (0x1 << 27) | (0x1 << 31)); + + setbits_le32(&ch[chn].phy.ca_dll_fine_tune[2], (0x1 << 11)); + clrbits_le32(&ch[chn].phy.b[0].dll_fine_tune[2], (0x1 << 11)); + clrbits_le32(&ch[chn].phy.b[1].dll_fine_tune[2], (0x1 << 11)); + udelay(2); + + setbits_le32(&ch[chn].phy.misc_cg_ctrl0, (0x1 << 4)); + udelay(1); + + /* DLL */ + setbits_le32(&ch[chn].phy.ca_dll_fine_tune[2], (0x1 << 0)); + udelay(1); + setbits_le32(&ch[chn].phy.b[0].dll_fine_tune[2], (0x1 << 0)); + udelay(1); + setbits_le32(&ch[chn].phy.b[1].dll_fine_tune[2], (0x1 << 0)); + udelay(1); + + clrbits_le32(&ch[chn].phy.ca_cmd[2], 0x1 << 21); + + save_restore_multi_reg(RESTORE_VALUE, + u4RegBackup, ARRAY_SIZE(u4RegBackup)); + + cke_fix_onoff(CKE_DYNAMIC, CHANNEL_A); + cke_fix_onoff(CKE_DYNAMIC, CHANNEL_B); + + setbits_le32(&ch[chn].phy.shu[0].pll[5], (0x1<<0)); + setbits_le32(&ch[chn].phy.shu[0].pll[7], (0x1<<0)); + setbits_le32(&ch[chn].phy.shu[0].pll[14], (0x1<<1)); + setbits_le32(&ch[chn].phy.shu[0].pll20, (0x1<<1)); + + clrsetbits_le32(&ch[chn].phy.shu[0].pll[14], + (0xffff<<16), 0x0208 << 16); + clrsetbits_le32(&ch[chn].phy.shu[0].pll20, + (0xffff<<16), 0x0208 << 16); + + clrsetbits_le32(&ch[chn].phy.shu[0].pll[15], + (0xffffffff<<0), 0xC03 << 16); + clrsetbits_le32(&ch[chn].phy.shu[0].pll21, + (0xffffffff<<0), 0xC03 << 16); +} + +static void update_initial_settings(void) +{ + u16 u2RXVrefDefault = 0x8; + u8 chn = 0; + + setbits_le32(&ch[0].ao.shu[0].odtctrl, (0x1 << 0)); + setbits_le32(&ch[0].phy.shu[0].b[0].dq[7], (0x1 << 15)); + setbits_le32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 15)); + + for (size_t b = 0; b < 2; b++) + for (size_t r = 0; r < 2; r++) + clrbits_le32(&ch[0].phy.r[r].b[b].rxdvs[2], + (0x1 << 23) | (0x1 << 28) | (0x3 << 30)); + clrbits_le32(&ch[0].phy.shu[0].ca_cmd[7], (0xf << 0)); + + setbits_le32(&ch[0].phy.ca_cmd[3], (0x1 << 10)); + setbits_le32(&ch[0].phy.ca_cmd[10], (0x1 << 5)); + clrsetbits_le32(&ch[0].phy.ca_cmd[6], 0x3 << 14, 0x1 << 14); + setbits_le32(&ch[0].phy.b[0].dq[3], + (0x1 << 5) | (0x1 << 6) | (0x1 << 7)); + setbits_le32(&ch[0].phy.b[1].dq[3], + (0x1 << 5) | (0x1 << 6) | (0x1 << 7)); + setbits_le32(&ch[0].phy.ca_cmd[3], (0x1 << 5) | (0x1 << 7)); + clrbits_le32(&ch[0].phy.b[0].dq[3], (0x1 << 1)); + clrbits_le32(&ch[0].phy.b[1].dq[3], (0x1 << 1)); + setbits_le32(&ch[0].phy.b[0].dq[5], (0x1 << 31)); + setbits_le32(&ch[0].phy.b[1].dq[5], (0x1 << 31)); + setbits_le32(&ch[0].phy.ca_cmd[5], (0x1 << 31)); + + clrsetbits_le32(&ch[0].phy.ca_cmd[6], 0xf << 16, 0x3 << 16); + clrsetbits_le32(&ch[0].phy.misc_imp_ctrl0, + (0x1 << 5) | (0x1 << 6), + (0x1 << 5) | (0x0 << 6)); + setbits_le32(&ch[0].phy.b[0].dq[6], (0x1 << 9)); + setbits_le32(&ch[0].phy.b[1].dq[6], (0x1 << 9)); + setbits_le32(&ch[0].phy.ca_cmd[6], (0x1 << 9)); + clrsetbits_le32(&ch[0].phy.b[0].dq[6], (0x3 << 0), (0x1 << 0)); + clrsetbits_le32(&ch[0].phy.b[1].dq[6], (0x1 << 0), (0x1 << 0)); + clrsetbits_le32(&ch[0].phy.ca_cmd[6], (0x3 << 0), (0x1 << 0)); + + setbits_le32(&ch[0].phy.ca_cmd[6], (0x1 << 6)); + setbits_le32(&ch[0].phy.b[0].dq[6], (0x1 << 3)); + setbits_le32(&ch[0].phy.b[1].dq[6], (0x1 << 3)); + setbits_le32(&ch[0].phy.ca_cmd[6], (0x1 << 3)); + setbits_le32(&ch[0].phy.b[0].dq[6], (0x1 << 5)); + setbits_le32(&ch[0].phy.b[1].dq[6], (0x1 << 5)); + setbits_le32(&ch[0].phy.ca_cmd[6], (0x1 << 5)); + + u2RXVrefDefault = 0xE; + for (u8 b = 0; b < 2; b++) { + clrsetbits_le32(&ch[0].phy.shu[0].b[b].dq[5], + (0x3f << 0), (u2RXVrefDefault << 0)); + clrsetbits_le32(&ch[0].phy.b[b].dq[5], + (0x3f << 8), (u2RXVrefDefault << 8)); + } + + for (chn = 0; chn < CHANNEL_NUM; chn++) { + setbits_le32(&ch[chn].phy.b[0].dq[8], + (0x1 << 0) | (0x1 << 1) | (0x1 << 2)); + setbits_le32(&ch[chn].phy.b[1].dq[8], + (0x1 << 0) | (0x1 << 1) | (0x1 << 2)); + setbits_le32(&ch[chn].phy.ca_cmd[9], + (0x1 << 0) | (0x1 << 1) | (0x1 << 2)); + + dramc_gating_mode(chn, 1); + } + + setbits_le32(&ch[0].phy.ca_cmd[8], (0x1 << 19)); + clrbits_le32(&ch[0].phy.ca_cmd[8], (0x1 << 18)); + clrsetbits_le32(&ch[0].ao.shu[0].misc, (0xf << 0), (0x2 << 0)); + clrsetbits_le32(&ch[0].ao.shu[0].dqsg, (0x3f << 20) | (0x1 << 16), + (0x2a << 20) | (0x1 << 16)); + + clrbits_le32(&ch[0].phy.shu[0].b[0].dq[5], (0x3f << 8)); + clrbits_le32(&ch[0].phy.shu[0].b[1].dq[5], (0x3f << 8)); + clrbits_le32(&ch[0].phy.shu[0].ca_cmd[5], (0x3f << 8)); + + dramc_broadcast_onoff(DRAMC_BROADCAST_OFF); + for (chn = 0; chn < CHANNEL_NUM; chn++) { + clrbits_le32(&ch[chn].phy.shu[0].b[0].dq[6], (0x3f << 0)); + clrbits_le32(&ch[chn].phy.shu[0].b[1].dq[6], (0x3f << 0)); + clrbits_le32(&ch[chn].phy.shu[0].ca_cmd[6], (0x3f << 0)); + } + dramc_broadcast_onoff(DRAMC_BROADCAST_ON); + + /* IMP Tracking Init Settings */ + clrsetbits_le32(&ch[0].ao.shu[0].impcal1, + (0x7 << 0) | (0x7 << 17) | (0xff << 20) | (0xf << 28), + (0x4 << 0) | (0x4 << 17) | (0x10 << 20) | (0x8 << 28)); + + setbits_le32(&ch[0].ao.srefctrl, (0xf << 12)); + setbits_le32(&ch[0].ao.pre_tdqsck[0], (0x1 << 17)); + + setbits_le32(&ch[0].ao.shu[0].misc, (0xf << 12)); + clrsetbits_le32(&ch[0].phy.shu[0].b[0].dq[8], + (0xffff << 0) | (0x1 << 15) | (0x3ff << 22), + (0x7fff << 0) | (0x0 << 15) | (0x3ff << 22)); + clrsetbits_le32(&ch[0].phy.shu[0].b[1].dq[8], + (0xffff << 0) | (0x1 << 15) | (0x3ff << 22), + (0x7fff << 0) | (0x0 << 15) | (0x3ff << 22)); + clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[8], + (0xffff << 0) | (0x1 << 15) | (0x3ff << 22), + (0x7fff << 0) | (0x0 << 15) | (0x3ff << 22)); + setbits_le32(&ch[0].phy.misc_ctrl3, (0x1 << 26)); + clrbits_le32(&ch[0].phy.shu[0].b[0].dq[7], + (0xf << 8) | (0x1 << 12) | (0x1 << 13)); + clrbits_le32(&ch[0].phy.shu[0].b[1].dq[7], + (0xf << 8) | (0x1 << 12) | (0x1 << 13)); + clrsetbits_le32(&ch[0].ao.clkar, + (0xffff << 0) | (0x1 << 15), + (0x7fff << 0) | (0x1 << 15)); + + clrbits_le32(&ch[0].ao.shu[0].dqsg_retry, (0x1 << 29)); + clrbits_le32(&ch[0].ao.write_lev, (0x1 << 2)); + setbits_le32(&ch[0].ao.dummy_rd, (0x1 << 24)); + clrbits_le32(&ch[0].ao.stbcal2, (0x1 << 0) | (0x1 << 1)); + setbits_le32(&ch[0].ao.eyescan, + (0x1 << 8) | (0x1 << 9) | (0x1 << 10)); + setbits_le32(&ch[0].ao.shu[0].odtctrl, (0x1 << 2) | (0x1 << 3)); + + setbits_le32(&ch[0].phy.shu[0].b[0].dll[0], (0x1 << 0)); + setbits_le32(&ch[0].phy.shu[0].b[1].dll[0], (0x1 << 0)); + setbits_le32(&ch[0].phy.ca_dll_fine_tune[1], (0x1 << 21)); + + setbits_le32(&ch[0].ao.perfctl0, + (0x1 << 15) | (0x1 << 19) | (0x1 << 26)); + setbits_le32(&ch[0].ao.srefctrl, (0x1 << 22)); + clrsetbits_le32(&ch[0].ao.shuctrl1, (0xff << 0), (0x1a << 0)); + setbits_le32(&ch[0].phy.b[0].dq[6], + (0x1 << 7) | (0x1 << 12)); + setbits_le32(&ch[0].phy.b[1].dq[6], + (0x1 << 7) | (0x1 << 12)); + setbits_le32(&ch[0].phy.ca_cmd[6], (0x1 << 7) | (0x1 << 12)); + setbits_le32(&ch[0].ao.stbcal2, (0x1 << 16)); + clrsetbits_le32(&ch[0].phy.shu[0].b[0].dq[7], + (0x7 << 29) | (0x1 << 28) | (0x7 << 25) | (0x1 << 24), + (0x0 << 29) | (0x1 << 28) | (0x1 << 25) | (0x1 << 24)); + clrsetbits_le32(&ch[0].phy.shu[0].b[1].dq[7], + (0x7 << 29) | (0x1 << 28) | (0x7 << 25) | (0x1 << 24), + (0x0 << 29) | (0x1 << 28) | (0x1 << 25) | (0x1 << 24)); + + /* Disable RODT tracking */ + clrbits_le32(&ch[0].ao.shu[0].rodtenstb, (0x1 << 0)); + + /* Rx Gating tracking settings */ + for (chn = 0; chn < CHANNEL_NUM; chn++) { + clrsetbits_le32(&ch[chn].ao.shu[0].dqsg, + (0x1 << 11) | (0xf << 12), + (0x1 << 11) | (0x9 << 12)); + clrsetbits_le32(&ch[chn].ao.shu[0].rk[0].dqscal, + (0x1 << 7) | (0x1 << 15), + (0x0 << 7) | (0x0 << 15)); + clrsetbits_le32(&ch[chn].ao.shu[0].rk[1].dqscal, + (0x1 << 7) | (0x1 << 15), + (0x0 << 7) | (0x0 << 15)); + clrsetbits_le32(&ch[chn].ao.shu[0].stbcal, + (0x7 << 4) | (0x1 << 8), + (0x1 << 4) | (0x1 << 8)); + } + + clrsetbits_le32(&ch[0].phy.b[0].dq[9], + (0xff << 8), (0x4 << 8)); + clrsetbits_le32(&ch[0].phy.b[1].dq[9], + (0xff << 8), (0x4 << 8)); + clrbits_le32(&ch[0].phy.ca_cmd[10], (0xff << 8)); + + setbits_le32(&ch[0].phy.shu[0].b[0].dq[8], (0x1 << 24)); + setbits_le32(&ch[0].phy.shu[0].b[1].dq[8], (0x1 << 24)); + + /* Enable WDQS */ + clrsetbits_le32(&ch[0].phy.shu[0].b[0].dll[1], + (0x1 << 16) | (0x1 << 17), + (0x0 << 16) | (0x1 << 17)); + clrsetbits_le32(&ch[0].phy.shu[0].b[1].dll[1], + (0x1 << 16) | (0x1 << 17), + (0x0 << 16) | (0x1 << 17)); + setbits_le32(&ch[0].ao.shu[0].odtctrl, + (0x1 << 0) | (0x1 << 30) | (0x1 << 31)); + setbits_le32(&ch[0].phy.shu[0].b[0].dq[7], (0x1 << 15)); + setbits_le32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 15)); + + setbits_le32(&ch[0].ao.drsctrl, (0x1 << 19)); + setbits_le32(&ch[0].ao.refctrl0, (0x1 << 28)); + setbits_le32(&ch[0].ao.zqcs, (0x1 << 19)); + setbits_le32(&ch[0].ao.dummy_rd, (0x3 << 26)); + setbits_le32(&ch[0].ao.shuctrl2, (0x1 << 8)); + clrsetbits_le32(&ch[0].ao.shuctrl3, + (0xff << 24), (0xb << 24)); + setbits_le32(&ch[0].phy.misc_ctrl3, (0x1 << 27)); + + setbits_le32(&ch[0].phy.b[0].dll_fine_tune[1], (0x3 << 20)); + setbits_le32(&ch[0].phy.b[1].dll_fine_tune[1], (0x3 << 20)); + setbits_le32(&ch[0].phy.ca_dll_fine_tune[1], (0x1 << 20)); + clrbits_le32(&ch[0].phy.misc_ctrl0, (0x1 << 27)); + setbits_le32(&ch[0].phy.misc_rxdvs[2], (0x1 << 8)); + setbits_le32(&ch[0].ao.clkctrl, (0x1 << 7)); + setbits_le32(&ch[0].ao.refctrl1, (0x1 << 7)); + clrsetbits_le32(&ch[0].ao.shuctrl, + (0x1 << 2) | (0x3 << 6) | (0x3 << 26), + (0x0 << 2) | (0x3 << 6) | (0x3 << 26)); + setbits_le32(&ch[0].ao.shuctrl2, (0x1 << 31) | (0x3 << 10)); + clrbits_le32(&ch[0].ao.stbcal2, (0xf << 4)); + clrbits_le32(&ch[0].ao.pre_tdqsck[0], (0x3 << 19)); + + setbits_le32(&ch[0].ao.ckectrl, (0x1 << 22)); + clrsetbits_le32(&ch[0].phy.ca_tx_mck, + (0x1 << 31) | (0x1f << 21) | (0x1f << 26), + (0x1 << 31) | (0xa << 21) | (0xa << 26)); + + /* MP setting should set CKECTRL_CKELCKFIX as 1 */ + setbits_le32(&ch[0].ao.ckectrl, (0x1 << 23)); + + /* Gating error problem happened in M17 + * has been solved by setting this RG as 0 */ + clrbits_le32(&ch[0].ao.shu[0].rodtenstb, (0x1 << 31)); +} + +static void dramc_power_on_sequence(void) +{ + u8 chn; + + /* reset dram = low */ + for (chn = 0; chn < CHANNEL_NUM; chn++) + clrbits_le32(&ch[chn].phy.misc_ctrl1, (0x1 << 13)); + + /* CKE low */ + cke_fix_onoff(CKE_FIXOFF, CHANNEL_A); + cke_fix_onoff(CKE_FIXOFF, CHANNEL_B); + + /* delay tINIT1=200us(min) & tINIT2=10ns(min)*/ + udelay(200); + + for (chn = 0; chn < CHANNEL_NUM; chn++) + setbits_le32(&ch[chn].phy.misc_ctrl1, (0x1 << 13)); + + /* Disable HW MIOCK control to make CLK always on */ + for (chn = 0; chn < CHANNEL_NUM; chn++) + setbits_le32(&ch[chn].ao.dramc_pd_ctrl, (0x1 << 26)); + + udelay(2000); + + /* CKE high */ + cke_fix_onoff(CKE_FIXON, CHANNEL_A); + cke_fix_onoff(CKE_FIXON, CHANNEL_B); + + udelay(2); + dramc_dbg("APPLY_LP4_POWER_INIT_SEQUENCE\n"); +} + +static void ddr_phy_reserved_rg_setting(void) +{ + u8 chn; + + /* fine tune */ + clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[6], + (0xFFFF << 6), (0x3 << 6) | (0x4 << 8) | (0x3 << 17)); + clrsetbits_le32(&ch[1].phy.shu[0].ca_cmd[6], + (0xFFFF << 6), (0x1 << 6) | (0x4 << 8) | (0x3 << 17)); + + for (chn = 0; chn < CHANNEL_NUM; chn++) { + clrsetbits_le32(&ch[chn].phy.shu[0].ca_dll[1], + (0xf << 9) | (0x1f << 16) | (0x7ff << 21), + (0x1 << 8) | (0x7 << 13) | (0x4 << 16)); + + for (u8 b = 0; b < 2; b++) { + clrsetbits_le32(&ch[chn].phy.shu[0].b[b].dq[6], + (0x3f << 11) | (0x7 << 19), + (0x1 << 6) | (0x1 << 10) | (0x3 << 17)); + + /* TX */ + clrsetbits_le32(&ch[chn].phy.shu[0].b[b].dll[1], + (0x3 << 8) | (0x3 << 11) | + (0x7 << 14) | (0x3fff << 18), + (0x1 << 10) | (0x1 << 13) | (0x1 << 17)); + } + } +} + +static void dramc_duty_set_clk_delay(u8 chn, s8 clkDelay) +{ + size_t rank; + u8 delay, delayb, revb0, revb1; + + delay = (clkDelay < 0) ? -clkDelay : 0; + delayb = (clkDelay < 0) ? 0 : clkDelay; + revb0 = (delay) ? 1 : 0; + revb1 = (delayb) ? 1 : 0; + + for (rank = 0; rank < RANK_MAX; rank++) { + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].ca_cmd[1], + (0xf << 24) | (0xf << 28), + (delay << 24) | (delay << 28)); + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].ca_cmd[0], + (0xf << 24) | (0xf << 28), + (delayb << 24) | (delayb << 28)); + } + clrsetbits_le32(&ch[chn].phy.shu[0].ca_cmd[3], + (0x3 << 8), (revb0 << 8) | (revb1 << 9)); +} + +static void dramc_duty_set_dqs_delay(u8 chn, s8 dqsDelay) +{ + size_t rank, dqs; + u8 delay, delayb, revb0, revb1; + + delay = (dqsDelay < 0) ? -dqsDelay : 0; + delayb = (dqsDelay < 0) ? 0 : dqsDelay; + revb0 = (delay) ? 1 : 0; + revb1 = (delayb) ? 1 : 0; + + for (rank = 0; rank < RANK_MAX; rank++) { + for (dqs = 0; dqs < DQS_NUMBER; dqs++) { + clrsetbits_le32( + &ch[chn].phy.shu[0].rk[rank].b[dqs].dq[1], + (0xf << 24) | (0xf << 28) | + (0xf << 16) | (0xf << 20), + (delay << 24) | (delay << 28) | + (delayb << 16) | (delayb << 20)); + + } + } + clrsetbits_le32(&ch[chn].phy.shu[0].b[0].dll[1], + (0x3 << 8), (revb0 << 8) | (revb1 << 9)); +} + +static void dramc_duty_calibration(u8 chn, s8 clkDelay, s8 dqsDelay) +{ + dramc_duty_set_clk_delay(chn, clkDelay); + dramc_duty_set_dqs_delay(chn, dqsDelay); +} + +static void dramc_mode_reg_init(void) +{ + u8 u1MR12Value[CHANNEL_NUM][RANK_MAX][FSP_MAX] = { + {{0x5d, 0x5d}, {0x5d, 0x5d} }, + {{0x5d, 0x5d}, {0x5d, 0x5d} }, + }; + + u8 u1MR14Value_06VDDQ[CHANNEL_NUM][RANK_MAX][FSP_MAX] = { + {{0x5d, 0x10}, {0x5d, 0x10} }, + {{0x5d, 0x10}, {0x5d, 0x10} }, + }; + + u8 chn, rank; + u32 broadcast_bak = get_dramc_broadcast(); + dramc_broadcast_onoff(DRAMC_BROADCAST_OFF); + + dramc_power_on_sequence(); + + /* Fix nWR value to 30 (MR01[6:4] = 101B) for DDR3200 + * Other vendors: Use default MR01 for each FSP + * (Set in vInitGlobalVariablesByCondition() ) + */ + + for (chn = 0; chn < CHANNEL_NUM; chn++) { + u8 u1MR2Value[FSP_MAX] = { 0x0b, 0x2d}; + u8 u1MR13Value_t = 0xc0 | (MR13_RRO << 4) | (1 << 3); + u8 u1MR01Value[FSP_MAX] = { 0x56, 0x56}; + u8 u1MR11Value[FSP_MAX] = { 0x0, 0x23}; + u8 u1MR13Value[FSP_MAX] = { 0x0 | (MR13_RRO << 4) | (1 << 3), + 0x40 | (MR13_RRO << 4) | (1 << 3)}; + u8 u1MR22Value[FSP_MAX] = {0x38, 0x34}; + for (rank = 0; rank < 2; rank++) { + dramc_dbg("%s CH%u RK%u\n", __func__, chn, rank); + clrsetbits_le32(&ch[chn].ao.mrs, + (0x3 << 24), (rank << 24)); + + /* ZQ calobration should be done before CBT calibration + * by switching to low frequency */ + dramc_zq_calibration(chn, rank); + + for (uint32_t fsp = FSP_0; fsp < FSP_MAX; fsp++) { + dramc_dbg("chn:%d,rank:%d,fsp%d\n", + chn, rank, fsp); + + dramc_mode_reg_write(chn, + 0xd, u1MR13Value[fsp]); + + /* MR12 use previous value + * MR12 VREF-CA */ + dramc_mode_reg_write(chn, + 0xc, u1MR12Value[chn][rank][fsp]); + dramc_mode_reg_write(chn, + 0x1, u1MR01Value[fsp]); + dramc_mode_reg_write(chn, + 0x2, u1MR2Value[fsp]); + dramc_mode_reg_write(chn, + 0xb, u1MR11Value[fsp]); /* ODT */ + + /* SOC-ODT, ODTE-CK, ODTE-CS, Disable ODTD-CA */ + dramc_mode_reg_write(chn, + 0x16, u1MR22Value[fsp]); + + /* MR14 use previous value + * MR14 VREF-DQ */ + dramc_mode_reg_write(chn, 0xe, + u1MR14Value_06VDDQ[chn][rank][fsp]); + + /* MR3 set write-DBI and read-DBI */ + u8 u1MR03Value = 0x30; + dramc_mode_reg_write(chn, 0x3, u1MR03Value); + } + } + + /* FSP-1 */ + u1MR13Value_t = 0xc0 | (MR13_RRO<<4) | (1<<3); + dramc_mode_reg_write_by_rank(chn, RANK_0, + 0xd, u1MR13Value_t); + dramc_mode_reg_write_by_rank(chn, RANK_1, + 0xd, u1MR13Value_t); + + clrsetbits_le32(&ch[chn].ao.shu[0].hwset_mr13, + (0x1fff << 0) | (0xff << 16), + (13 << 0) | ((u1MR13Value_t | 0x1 << 3) << 16)); + + clrsetbits_le32(&ch[chn].ao.shu[0].hwset_vrcg, + (0x1fff << 0) | (0xff << 16), + (13 << 0) | ((u1MR13Value_t | (0x1 << 3)) << 16)); + + clrsetbits_le32(&ch[chn].ao.shu[0].hwset_mr2, + (0x1fff << 0) | (0xff << 16), + (2 << 0) | (u1MR2Value[FSP_1] << 16)); + } + + clrsetbits_le32(&ch[0].ao.mrs, (0x3 << 24), (RANK_0 << 24)); + clrsetbits_le32(&ch[1].ao.mrs, (0x3 << 24), (RANK_0 << 24)); + + dramc_broadcast_onoff(broadcast_bak); +} + +static u8 get_cbt_mode(const struct sdram_params *params) +{ + return params->cbt_mode_extern; +} + +static void dramc_setting(const struct sdram_params *params) +{ + u8 chn; + + auto_refresh_cke_off(); + dramc_broadcast_onoff(DRAMC_BROADCAST_OFF); + + /* before switch clock from 26M to PHY, need to init PHY clock first + * move CKMUX_SEL_R_PHYCTRLMUX to here (it was originally between + * MISC_CG_CTRL0_CLK_MEM_SEL and MISC_CTRL0_R_DMRDSEL_DIV2_OPT) + * PHYCTRLDCM 1: follow DDRPHY_conf DCM settings, + * 0: follow infra DCM settings */ + for (chn = 0; chn < CHANNEL_NUM; chn++) + setbits_le32(&ch[chn].phy.ckmux_sel, + (0x1 << 0) | (0x1 << 1)); + + dramc_broadcast_onoff(DRAMC_BROADCAST_ON); + + setbits_le32(&ch[0].phy.misc_cg_ctrl0, (0x1 << 0)); + + /* 26M */ + clrbits_le32(&ch[0].phy.misc_cg_ctrl0, (0x3 << 4)); + clrbits_le32(&ch[0].phy.misc_ctrl0, (0x1 << 17)); + + /* LP4_3200_initial_setting_shu1 begin */ + clrbits_le32(&ch[0].phy.misc_spm_ctrl1, (0x0000000f << 0)); + write32(&ch[0].phy.misc_spm_ctrl2, ~(0xffffffff << 0)); + write32(&ch[0].phy.misc_spm_ctrl0, ~(0xffffffff << 0)); + + write32(&ch[0].phy.misc_cg_ctrl2, 0x6003bf); + write32(&ch[0].phy.misc_cg_ctrl4, 0x333f3f00); + setbits_le32(&ch[0].phy.shu[0].pll[1], (0x1 << 4)|(0x7 << 1)); + clrsetbits_le32(&ch[0].phy.shu[0].b[0].dq[7], + (0x3f << 0), (0x10 << 0)); /* combine */ + clrbits_le32(&ch[0].phy.shu[0].b[1].dq[7], (0x0f << 0)); + + clrsetbits_le32(&ch[0].phy.shu[0].pll[4], + (0x3 << 18) | (0x3 << 24) | (0x3 << 26), + (0x2 << 18) | (0x1 << 24) | (0x1 << 26)); + clrsetbits_le32(&ch[0].phy.shu[0].pll[6], + (0x3 << 18) | (0x3 << 24) | (0x3 << 26), + (0x2 << 18) | (0x1 << 24) | (0x1 << 26)); + + clrbits_le32(&ch[0].phy.shu[0].pll[14], (0x1 << 1)); + clrbits_le32(&ch[0].phy.shu[0].pll20, (0x1 << 1)); + clrbits_le32(&ch[0].phy.ca_cmd[2], (0x3 << 16) | (0x3 << 20)); + for (size_t b = 0; b < 2; b++) + clrbits_le32(&ch[0].phy.b[b].dq[2], + (0x3 << 16) | (0x3 << 20)); + for (size_t b = 0; b < 2; b++) + clrsetbits_le32(&ch[0].phy.b[b].dq[9], + (0x7 << 28), (0x1 << 28)); + clrbits_le32(&ch[0].phy.ca_cmd[10], (0x7 << 28)); + + setbits_le32(&ch[0].phy.b0_rxdvs[0], (0x1 << 28)); + setbits_le32(&ch[0].phy.b1_rxdvs[0], (0x1 << 28)); + setbits_le32(&ch[0].phy.b0_rxdvs[0], (0x1 << 9)); + setbits_le32(&ch[0].phy.b1_rxdvs[0], (0x1 << 9)); + + for (size_t b = 0; b < 2; b++) { + for (size_t r = 0; r < 2; r++) + setbits_le32(&ch[0].phy.r[r].b[b].rxdvs[2], + (0x1 << 29)); + clrsetbits_le32(&ch[0].phy.shu[0].b[b].dq[5], + (0x7 << 20), (0x3 << 20)); + + for (size_t r = 0; r < 2; r++) { + clrsetbits_le32(&ch[0].phy.r[r].b[b].rxdvs[1], + (0xffff << 0) | (0xffff << 16), + (0x2 << 0) | (0x2 << 16)); + clrsetbits_le32(&ch[0].phy.r[r].b[b].rxdvs[2], + (0x1 << 23) | (0x1 << 28) | (0x3 << 30), + (0x1 << 23) | (0x1 << 28) | (0x2 << 30)); + } + } + + clrbits_le32(&ch[0].phy.b0_rxdvs[0], (0x1 << 28)); + clrbits_le32(&ch[0].phy.b1_rxdvs[0], (0x1 << 28)); + + for (size_t b = 0; b < 2; b++) { + setbits_le32(&ch[0].phy.b[b].dq[9], (0x1 << 0)); + + for (size_t r = 0; r < 2; r++) + clrsetbits_le32(&ch[0].phy.shu[0].rk[r].b[b].dq[7], + (0x3f << 8) | (0x3f << 16), + (0x1f << 8) | (0x1f << 16)); + + clrsetbits_le32(&ch[0].phy.b[b].dq[4], + (0x7f << 0) | (0x7f << 8), + (0x10 << 0) | (0x10 << 8)); + clrsetbits_le32(&ch[0].phy.b[b].dq[5], + (0xff << 0) | (0x3f << 8) | (0x1 << 16) | (0xf << 20) | + (0x1 << 24), + (0x10 << 0) | (0xe << 8) | (0x1 << 16) | (0x1 << 20) | + (0x0 << 24)); + clrsetbits_le32(&ch[0].phy.b[b].dq[6], + (0x1 << 4) | (0x1 << 7) | (0x1 << 12) | (0x3 << 14) | + (0xf << 16) | (0x1 << 24), + (0x0 << 4) | (0x1 << 7) | (0x1 << 12) | (0x0 << 14) | + (0x3 << 16) | (0x1 << 24)); + clrsetbits_le32(&ch[0].phy.b[b].dq[5], + (0xff << 0) | (0x1 << 25), + (0x0 << 0) | (0x1 << 25)); + } + + setbits_le32(&ch[0].phy.ca_cmd[3], + (0x1 << 2) | (0x1 << 3) | (0x1 << 7)); + clrsetbits_le32(&ch[0].phy.ca_cmd[6], + (0x1 << 6) | (0x3 << 14) | (0x1 << 16), + (0x0 << 6) | (0x0 << 14) | (0x0 << 16)); + + clrbits_le32(&ch[0].phy.pll3, (0x1 < 0)); + setbits_le32(&ch[0].phy.b[0].dq[3], (0x1 << 3)); + setbits_le32(&ch[0].phy.b[1].dq[3], (0x1 << 3)); + + udelay(1); + clrsetbits_le32(&ch[0].phy.shu[0].pll[8], + (0x7 << 0) | (0x3 << 18), + (0x0 << 0) | (0x1 << 18)); + + udelay(1); + clrbits_le32(&ch[0].phy.shu[0].pll[9], + (0x3 << 8) | (0x1 << 12) | (0x3 << 14) | (0x1 << 16)); + clrbits_le32(&ch[0].phy.shu[0].pll[11], + (0x3 << 8) | (0x1 << 12) | (0x3 << 14) | (0x1 << 16)); + udelay(1); + + clrsetbits_le32(&ch[0].phy.shu[0].pll[10], + (0x7 << 0) | (0x3 << 18), (0x0 << 0) | (0x1 << 18)); + udelay(1); + + /* PLL EN */ + /* MID FINE_TUNE Init 1 */ + clrsetbits_le32(&ch[0].phy.pll4, + (0x3 << 18) | (0x1 << 21), (0x3 << 18) | (0x0 << 21)); + + udelay(1); + clrsetbits_le32(&ch[0].phy.shu[0].pll[0], + (0xffff << 0), (0x3 << 0)); + + udelay(1); + setbits_le32(&ch[0].phy.ca_dll_fine_tune[1], (0x1 << 21)); + + for (size_t b = 0; b < 2; b++) { + setbits_le32(&ch[0].phy.b[b].dq[3], + (0x3 << 1) | (0x1 << 10)); + } + + dramc_broadcast_onoff(DRAMC_BROADCAST_OFF); + setbits_le32(&ch[0].phy.shu[0].ca_dll[0], (0x1 << 0)); + setbits_le32(&ch[1].phy.shu[0].ca_dll[0], (0x1 << 0)); + dramc_broadcast_onoff(DRAMC_BROADCAST_ON); + + for (size_t b = 0; b < 2; b++) + clrsetbits_le32(&ch[0].phy.shu[0].b[b].dll[0], + (0x1 << 4) | (0x3 << 9) | (0xf << 12) | + (0xf << 16) | (0xf << 20) | (0x1 << 30), + (0x0 << 4) | (0x3 << 9) | (0x8 << 12) | + (0x7 << 16) | (0x7 << 20) | (0x1 << 30)); + + clrbits_le32(&ch[0].phy.shu[0].ca_cmd[5], (0x3f << 0)); + clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[0], + (0x1 << 4) | (0x7 << 12) | (0x1 << 20), + (0x1 << 4) | (0x4 << 12) | (0x1 << 20)); + + + dramc_broadcast_onoff(DRAMC_BROADCAST_OFF); + clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[6], + (0xffff << 6), (0x3 << 6)); + clrsetbits_le32(&ch[1].phy.shu[0].ca_cmd[6], + (0xffff << 6), (0x1 << 6)); + dramc_broadcast_onoff(DRAMC_BROADCAST_ON); + + for (size_t b = 0; b < 2; b++) + clrsetbits_le32(&ch[0].phy.shu[0].b[b].dq[6], + (0xffff << 6), 0x1 << 6); + + dramc_broadcast_onoff(DRAMC_BROADCAST_OFF); + clrsetbits_le32(&ch[0].phy.misc_shu_opt, + (0x1 << 0) | (0x3 << 2) | (0x1 << 8) | + (0x3 << 10) | (0x1 << 16) | (0x3 << 18), + (0x1 << 0) | (0x2 << 2) | (0x1 << 8) | + (0x2 << 10) | (0x1 << 16) | (0x1 << 18)); + clrsetbits_le32(&ch[1].phy.misc_shu_opt, + (0x1 << 0) | (0x3 << 2) | (0x1 << 8) | + (0x3 << 10) | (0x1 << 16) | (0x3 << 18), + (0x1 << 0) | (0x2 << 2) | (0x1 << 8) | + (0x2 << 10) | (0x1 << 16) | (0x2 << 18)); + dramc_broadcast_onoff(DRAMC_BROADCAST_ON); + udelay(9); + + dramc_broadcast_onoff(DRAMC_BROADCAST_OFF); + clrsetbits_le32(&ch[0].phy.shu[0].ca_dll[1], + (0x1 << 0) | (0x1 << 2), (0x1 << 2)); + clrsetbits_le32(&ch[1].phy.shu[0].ca_dll[1], + (0x1 << 0) | (0x1 << 2), (0x1 << 0)); + dramc_broadcast_onoff(DRAMC_BROADCAST_ON); + + for (size_t b = 0; b < 2; b++) { + clrsetbits_le32(&ch[0].phy.shu[0].b[b].dll[1], + (0x1 << 0) | (0x1 << 2), (0x1 << 0) | (0x0 << 2)); + } + + udelay(1); + + clrbits_le32(&ch[0].phy.pll2, (0x1 << 31)); + clrsetbits_le32(&ch[0].phy.misc_cg_ctrl0, 0xFFFFFFFF, 0xF); + + udelay(1); + + dramc_broadcast_onoff(DRAMC_BROADCAST_OFF); + ddr_phy_reserved_rg_setting(); + + for (chn = 0; chn < CHANNEL_NUM; chn++) + ddr_phy_pll_setting(chn); + dramc_broadcast_onoff(DRAMC_BROADCAST_ON); + + setbits_le32(&ch[0].ao.drsctrl, (0x1 << 29)); + /* Set Run time MRR CKE fix to 1 in tMRRI old mode + * to avoid no ACK from precharge all */ + setbits_le32(&ch[0].ao.ckectrl, (0x1 << 27)); + clrsetbits_le32(&ch[0].ao.dramctrl, + (0x1 << 15) | (0x1 << 17) | (0x1 << 23), + (0x0 << 15) | (0x1 << 17) | (0x1 << 23)); + setbits_le32(&ch[0].ao.spcmdctrl, + (0x1 << 1) | (0x1 << 8) | (0x1 << 9) | (0x1 << 10)); + setbits_le32(&ch[0].phy.b[0].dq[9], (0x1 << 4)); + setbits_le32(&ch[0].phy.b[1].dq[9], (0x1 << 4)); + + clrsetbits_le32(&ch[0].ao.shu[0].rk[1].dqsien, + (0x7f << 0) | (0x7f << 8) | (0x7f << 16) | (0x7f << 24), + (0xf << 0) | (0xf << 8) | (0xf << 16) | (0xf << 24)); + clrsetbits_le32(&ch[0].ao.stbcal1, + (0x1 << 4) | (0x1 << 8) | (0x1 << 12), + (0x1 << 4) | (0x1 << 8) | (0x0 << 12)); + clrsetbits_le32(&ch[0].ao.shu[0].dqsg_retry, + (0x1 << 3) | (0xf << 8) | (0x1 << 21) | (0x1 << 31), + (0x1 << 3) | (0x6 << 8) | (0x1 << 21) | (0x1 << 31)); + + for (size_t i = 0; i < 4; i++) { + clrsetbits_le32(&ch[0].ao.shu[0].drving[i], + (0x1f << 0) | (0x1f << 5) | (0x1f << 10) + | (0x1f << 15) | (0x1f << 20) | (0x1f << 25), + (0xa << 0) | (0xa << 5) | (0xa << 10) + | (0xa << 15) | (0xa << 20) | (0xa << 25)); + } + + clrsetbits_le32(&ch[0].ao.shuctrl2, + (0x3f << 0) | (0x1 << 12) | (0x1 << 14) | + (0x1 << 15) | (0xff << 16) | (0x1 << 24), + (0xa << 0) | (0x1 << 12) | (0x1 << 14) | + (0x1 << 15) | (0x1 << 16) | (0x0 << 24)); + setbits_le32(&ch[0].ao.dvfsdll, (0x1 << 0)); + setbits_le32(&ch[0].ao.ddrconf0, + (0x1 << 12) | (0x1 << 15) | (0x1 << 20) | (0x1 << 26)); + setbits_le32(&ch[0].ao.stbcal2, + (0x1 << 4) | (0x1 << 28) | (0x1 << 30)); + setbits_le32(&ch[0].ao.stbcal2, (0x1 << 29)); + clrbits_le32(&ch[0].ao.stbcal2, (0x1 << 29)); + setbits_le32(&ch[0].ao.clkar, (0x1 << 19)); + + for (size_t b = 0; b < 2; b++) + clrsetbits_le32(&ch[0].phy.b[b].dq[9], + (0x7 << 20), (0x1 << 20)); + clrsetbits_le32(&ch[0].phy.ca_cmd[10], + (0x7 << 20), (0x0 << 20)); + + if (get_cbt_mode(params) == CBT_BYTE_MODE1) + clrsetbits_le32(&ch[0].phy.misc_ctrl0, + (0xf << 0) | (0x1 << 9) | (0x7 << 18) | + (0x1 << 24) | (0x1 << 31), + (0xf << 0) | (0x1 << 9) | (0x1 << 18) | + (0x1 << 24) | (0x1 << 31)); + else + setbits_le32(&ch[0].phy.misc_ctrl0, + (0xf << 0) | (0x1 << 9) | (0x1 << 24) | (0x1 << 31)); + + for (chn = 0; chn < CHANNEL_NUM; chn++) + setbits_le32(&ch[chn].phy.misc_ctrl1, + (0x1 << 2) | (0x1 << 3) | (0x1 << 15) | (0x1 << 24)); + clrsetbits_le32(&ch[0].phy.b0_rxdvs[0], + (0x1 << 24), (0x1 << 24)); + clrsetbits_le32(&ch[0].phy.b1_rxdvs[0], + (0x1 << 24), (0x1 << 24)); + + clrsetbits_le32(&ch[0].phy.ca_rxdvs0, (0x1 << 24), (0x0 << 24)); + + clrbits_le32(&ch[0].phy.ca_cmd[7], (0x1 << 4)|(0x1 << 6)); + clrbits_le32(&ch[0].phy.b[0].dq[7], (0x1 << 6)); + clrbits_le32(&ch[0].phy.b[1].dq[7], (0x1 << 6)); + + clrsetbits_le32(&ch[0].ao.shu[0].conf[0], + (0x3f << 0) | (0x1 << 7) | (0xf << 12) | (0x1 << 24) | + (0x1 << 29) | (0x3 << 30), + (0x3f << 0) | (0x1 << 7) | (0x1 << 12) | (0x1 << 24) | + (0x1 << 29) | (0x2 << 30)); + clrsetbits_le32(&ch[0].ao.shu[0].odtctrl, + (0x1 << 0) | (0x1 << 1) | (0x7f << 16) | (0x1 << 30) | + (0x1 << 31), + (0x1 << 0) | (0x1 << 1) | (0x1 << 16) | (0x1 << 30) | + (0x1 << 31)); + setbits_le32(&ch[0].phy.shu[0].b[0].dq[7], (0x1 << 15)); + setbits_le32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 15)); + + clrsetbits_le32(&ch[0].ao.refctrl0, (0xf << 24), (0x5 << 24)); + clrbits_le32(&ch[0].ao.shu[0].selph_ca1, + (0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) | + (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28)); + clrsetbits_le32(&ch[0].ao.shu[0].selph_ca2, + (0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 16) | + (0x7 << 24), + (0x0 << 0) | (0x0 << 4) | (0x0 << 8) | (0x7 << 16) | + (0x0 << 24)); + clrbits_le32(&ch[0].ao.shu[0].selph_ca3, + (0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) | + (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28)); + clrbits_le32(&ch[0].ao.shu[0].selph_ca4, + (0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) | + (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28)); + clrbits_le32(&ch[0].ao.shu[0].selph_ca5, (0x7 << 8)); + clrsetbits_le32(&ch[0].ao.shu[0].selph_dqs0, + (0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) | + (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28), + (0x3 << 0) | (0x3 << 4) | (0x3 << 8) | (0x3 << 12) | + (0x3 << 16) | (0x3 << 20) | (0x3 << 24) | (0x3 << 28)); + clrsetbits_le32(&ch[0].ao.shu[0].selph_dqs1, + (0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) | + (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28), + (0x5 << 0) | (0x5 << 4) | (0x5 << 8) | (0x5 << 12) | + (0x2 << 16) | (0x2 << 20) | (0x2 << 24) | (0x2 << 28)); + + for (size_t i = 0; i < 2; i++) { + clrsetbits_le32(&ch[0].ao.shu[0].rk[i].selph_dq[0], + (0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) | + (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28), + (0x3 << 0) | (0x3 << 4) | (0x3 << 8) | (0x3 << 12) | + (0x3 << 16) | (0x3 << 20) | (0x3 << 24) | (0x3 << 28)); + clrsetbits_le32(&ch[0].ao.shu[0].rk[i].selph_dq[1], + (0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) | + (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28), + (0x3 << 0) | (0x3 << 4) | (0x3 << 8) | (0x3 << 12) | + (0x3 << 16) | (0x3 << 20) | (0x3 << 24) | (0x3 << 28)); + clrsetbits_le32(&ch[0].ao.shu[0].rk[i].selph_dq[2], + (0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) | + (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28), + (0x3 << 0) | (0x3 << 4) | (0x3 << 8) | (0x3 << 12) | + (0x1 << 16) | (0x1 << 20) | (0x1 << 24) | (0x1 << 28)); + clrsetbits_le32(&ch[0].ao.shu[0].rk[i].selph_dq[3], + (0x7 << 0) | (0x7 << 4) | (0x7 << 8) | (0x7 << 12) | + (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28), + (0x3 << 0) | (0x3 << 4) | (0x3 << 8) | (0x3 << 12) | + (0x1 << 16) | (0x1 << 20) | (0x1 << 24) | (0x1 << 28)); + } + + for (int b = 0; b < 2; b++) { + clrsetbits_le32(&ch[0].phy.shu[0].rk[0].b[b].dq[7], + (0x3f << 8) | (0x3f << 16), + (0x1a << 8) | (0x1a << 16)); + clrsetbits_le32(&ch[0].phy.shu[0].rk[1].b[b].dq[7], + (0x3f << 8) | (0x3f << 16), + (0x14 << 8) | (0x14 << 16)); + } + + udelay(1); + + for (size_t b = 0; b < 2; b++) { + setbits_le32(&ch[0].phy.b[b].dq[9], (0x1 << 5)); + clrsetbits_le32(&ch[0].phy.b[b].dq[6], + (0x3 << 14), (0x1 << 14)); + } + setbits_le32(&ch[0].ao.stbcal, (0x1 << 31)); + clrsetbits_le32(&ch[0].ao.srefctrl, + (0xf << 24) | (0x1 << 30), (0x8 << 24) | (0x0 << 30)); + clrsetbits_le32(&ch[0].ao.shu[0].ckectrl, + (0x3 << 24) | (0x3 << 28), + (0x3 << 24) | (0x3 << 28)); + setbits_le32(&ch[0].ao.shu[0].pipe, (0x1 << 30) | (0x1 << 31)); + setbits_le32(&ch[0].ao.ckectrl, (0x1 << 13) | (0x1 << 31)); + setbits_le32(&ch[0].ao.rkcfg, (0x1 << 2)); + + if (get_cbt_mode(params) == CBT_BYTE_MODE1) { + clrsetbits_le32(&ch[0].ao.shu[0].conf[2], + (0x7 << 16) | (0x1 << 28), (0x7 << 16) | (0x1 << 28)); + clrsetbits_le32(&ch[0].ao.spcmdctrl, + (0x1 << 26), (0x1 << 26)); + clrsetbits_le32(&ch[0].ao.shuctrl1, (0xff << 0), (0x40 << 0)); + } else { + clrsetbits_le32(&ch[0].ao.shu[0].conf[2], + (0x7 << 16) | (0x1 << 28), (0x7 << 16) | (0x1 << 28)); + clrsetbits_le32(&ch[0].ao.spcmdctrl, + (0x1 << 26), (0x1 << 26)); + clrsetbits_le32(&ch[0].ao.shuctrl1, (0xff << 0), (0x40 << 0)); + } + + setbits_le32(&ch[0].ao.shuctrl, (0x1 << 16)); + clrbits_le32(&ch[0].ao.refctrl1, + (0x1 << 1) | (0x1 << 2) | (0x1 << 3) | (0x1 << 6)); + + clrsetbits_le32(&ch[0].ao.refratre_filter, (0x1 << 15) | (0x1 << 23), + (0x1 << 15) | (0x0 << 23)); + + clrbits_le32(&ch[0].ao.dramctrl, (0x1 << 9)); + setbits_le32(&ch[0].ao.misctl0, + (0x1 << 19) | (0x1 << 24) | (0x1 << 31)); + setbits_le32(&ch[0].ao.perfctl0, + (0x1 << 0) | (0x1 << 1) | (0x1 << 4) | (0x1 << 8) | + (0x1 << 9) | (0x1 << 10) | (0x1 << 11) | + (0x1 << 14) | (0x1 << 17)); + clrsetbits_le32(&ch[0].ao.arbctl, (0xff << 0), (0x80 << 0)); + clrsetbits_le32(&ch[0].ao.padctrl, + (0x3 << 0) | (0x1 << 3), (0x1 << 0) | (0x1 << 3)); + setbits_le32(&ch[0].ao.dramc_pd_ctrl, (0x1 << 8)); + setbits_le32(&ch[0].ao.clkctrl, (0x1 << 29)); + clrsetbits_le32(&ch[0].ao.refctrl0, + (0x1 << 0) | (0x7 << 12), (0x1 << 0) | (0x4 << 12)); + + clrsetbits_le32(&ch[0].ao.shu[0].rankctl, + (0xf << 20) | (0xf << 24) | (0xf << 28), + (0x4 << 20) | (0x4 << 24) | (0x6 << 28)); + + udelay(2); + + if (get_cbt_mode(params) == CBT_NORMAL_MODE) { + clrsetbits_le32(&ch[0].ao.shu[0].rk[0].dqsien, + (0x7f << 0) | (0x7f << 8), (0x19 << 0) | (0x19 << 8)); + clrsetbits_le32(&ch[0].ao.shu[0].rk[1].dqsien, + (0x7f << 0) | (0x7f << 8) | (0x7f << 16) | (0x7f << 24), + (0x1b << 0) | (0x1b << 8) | (0x0 << 16) | (0x0 << 24)); + } + + setbits_le32(&ch[0].ao.dramctrl, (0x1 << 19)); + clrsetbits_le32(&ch[0].ao.zqcs, (0xff << 0), (0x56 << 0)); + udelay(1); + + clrsetbits_le32(&ch[0].ao.shu[0].conf[3], + (0x1ff << 16), (0xff << 16)); + setbits_le32(&ch[0].ao.refctrl0, (0x1 << 30)); + setbits_le32(&ch[0].ao.srefctrl, (0x1 << 30)); + setbits_le32(&ch[0].ao.mpc_option, (0x1 << 17)); + setbits_le32(&ch[0].ao.dramc_pd_ctrl, (0x1 << 30)); + setbits_le32(&ch[0].ao.dramc_pd_ctrl, (0x1 << 0)); + clrsetbits_le32(&ch[0].ao.eyescan, + (0x1 << 1) | (0xf << 16), (0x0 << 1) | (0x1 << 16)); + setbits_le32(&ch[0].ao.stbcal1, (0x1 << 10) | (0x1 << 11)); + clrsetbits_le32(&ch[0].ao.test2_1, (0xfffffff << 4), (0x10000 << 4)); + clrsetbits_le32(&ch[0].ao.test2_2, (0xfffffff << 4), (0x400 << 4)); + clrsetbits_le32(&ch[0].ao.test2_3, + (0x1 << 7) | (0x7 << 8) | (0x1 << 28), + (0x1 << 7) | (0x4 << 8) | (0x1 << 28)); + clrbits_le32(&ch[0].ao.rstmask, (0x1 << 29)); + clrbits_le32(&ch[0].ao.rstmask, (0x1 << 30)); + + udelay(1); + clrsetbits_le32(&ch[0].ao.hw_mrr_fun, (0xf << 0) | (0xf << 4), + (0x8 << 0) | (0x6 << 4)); + + if (get_cbt_mode(params) == CBT_BYTE_MODE1) { + setbits_le32(&ch[0].ao.perfctl0, (0x1 << 27)); + clrsetbits_le32(&ch[0].ao.perfctl0, + (0x1 << 18) | (0x1 << 19), (0x0 << 18) | (0x1 << 19)); + clrbits_le32(&ch[0].ao.rstmask, (0x1 << 28)); + setbits_le32(&ch[0].ao.rkcfg, (0x1 << 11)); + setbits_le32(&ch[0].ao.spcmdctrl, (0x1 << 28)); + setbits_le32(&ch[0].ao.eyescan, (0x1 << 2)); + } else { + clrbits_le32(&ch[0].ao.dramctrl, (0x1 << 0)); + clrsetbits_le32(&ch[0].ao.perfctl0, + (0x1 << 18) | (0x1 << 19), + (0x0 << 18) | (0x1 << 19)); + setbits_le32(&ch[0].ao.spcmdctrl, (0x1 << 28)); + clrbits_le32(&ch[0].ao.rstmask, (0x1 << 28)); + setbits_le32(&ch[0].ao.rkcfg, (0x1 << 11)); + setbits_le32(&ch[0].ao.mpc_option, (0x1 << 17)); + setbits_le32(&ch[0].ao.eyescan, (0x1 << 2)); + setbits_le32(&ch[0].ao.shu[0].wodt, (0x1 << 29)); + setbits_le32(&ch[0].phy.shu[0].b[0].dq[7], (0x1 << 7)); + setbits_le32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 7)); + clrsetbits_le32(&ch[0].ao.shu[0].rankctl, (0xf << 20), + (0x4 << 20)); + + for (size_t r = 0; r < 2; r++) { + clrsetbits_le32(&ch[0].ao.shu[0].rk[r].selph_dq[0], + (0x7 << 0) | (0x7 << 4), + (0x2 << 0) | (0x2 << 4)); + clrsetbits_le32(&ch[0].ao.shu[0].rk[r].selph_dq[1], + (0x7 << 0) | (0x7 << 4), + (0x2 << 0) | (0x2 << 4)); + } + } + udelay(5); + + clrsetbits_le32(&ch[0].ao.stbcal1, (0xffff << 16), (0x3 << 16)); + clrsetbits_le32(&ch[0].ao.stbcal1, (0xffff << 16), (0x1 << 16)); + clrsetbits_le32(&ch[0].ao.stbcal, + (0x1 << 0) | (0x1 << 22) | (0x1 << 24) | + (0x1 << 26) | (0x1 << 27), + (0x1 << 0) | (0x0 << 22) | (0x0 << 24) | + (0x1 << 26) | (0x1 << 27)); + setbits_le32(&ch[0].ao.stbcal1, (0x1 << 6)); + clrsetbits_le32(&ch[0].ao.shu[0].dqsg, + (0x1 << 11) | (0xf << 12), (0x1 << 11) | (0x9 << 12)); + clrbits_le32(&ch[0].phy.misc_ctrl0, (0xf << 0)); + setbits_le32(&ch[0].ao.shu[0].stbcal, (0x1 << 8)); + setbits_le32(&ch[0].ao.stbcal, (0x1 << 17)); + + clrbits_le32(&ch[0].phy.shu[0].b[0].dq[7], (0x1 << 14)); + clrbits_le32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 14)); + clrsetbits_le32(&ch[0].ao.shu[0].stbcal, (0x7 << 4), (0x1 << 4)); + + clrsetbits_le32(&ch[0].ao.shu[0].stbcal, (0x3 << 0), (0x2 << 0)); + + setbits_le32(&ch[0].ao.refctrl1, (0x1 << 0) | (0x1 << 5)); + setbits_le32(&ch[0].ao.dqsoscr, (0x1 << 23) | (0x1 << 27)); + clrbits_le32(&ch[0].ao.rstmask, + (0x1 << 24) | (0x1 << 25) | (0x1 << 26)); + clrsetbits_le32(&ch[0].ao.rkcfg, (0x7 << 4), (0x1 << 4)); + + udelay(12); + + if (get_cbt_mode(params) == CBT_BYTE_MODE1) { + clrsetbits_le32(&ch[0].ao.shu[0].rankctl, + (0xf << 20) | (0xf << 24) | (0xf << 28), + (0x3 << 20) | (0x3 << 24) | (0x5 << 28)); + } else { + clrsetbits_le32(&ch[0].ao.shu[0].rankctl, + (0xf << 24) | (0xf << 28), + (0x4 << 24) | (0x6 << 28)); + } + + clrbits_le32(&ch[0].ao.shu[0].wodt, (0x1 << 31)); + if (get_cbt_mode(params) == CBT_BYTE_MODE1) { + clrsetbits_le32(&ch[0].ao.shu[0].rk[0].dqsien, + (0x7f << 0) | (0x7f << 8), (0x19 << 0) | (0x19 << 8)); + } + clrsetbits_le32(&ch[0].ao.shu[0].rk[0].fine_tune, + (0x3f << 0) | (0x3f << 8) | (0x3f << 16) | (0x3f << 24), + (0x1a << 0) | (0x1a << 8) | (0x1a << 16) | (0x1a << 24)); + clrsetbits_le32(&ch[0].ao.shu[0].rk[0].selph_dq[2], + (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28), + (0x4 << 16) | (0x4 << 20) | (0x4 << 24) | (0x4 << 28)); + clrsetbits_le32(&ch[0].ao.shu[0].rk[0].selph_dq[3], + (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28), + (0x4 << 16) | (0x4 << 20) | (0x4 << 24) | (0x4 << 28)); + if (get_cbt_mode(params) == CBT_BYTE_MODE1) { + clrsetbits_le32(&ch[0].ao.shu[0].rk[1].dqsien, + (0x7f << 0) | (0x7f << 8) | (0x7f << 16) | (0x7f << 24), + (0x1b << 0) | (0x1b << 8) | (0x0 << 16) | (0x0 << 24)); + } + clrsetbits_le32(&ch[0].ao.shu[0].rk[1].fine_tune, + (0x3f << 0) | (0x3f << 8) | (0x3f << 16) | (0x3f << 24), + (0x14 << 0) | (0x14 << 8) | (0x14 << 16) | (0x14 << 24)); + clrsetbits_le32(&ch[0].ao.shu[0].rk[1].selph_dq[2], + (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28), + (0x4 << 16) | (0x4 << 20) | (0x4 << 24) | (0x4 << 28)); + clrsetbits_le32(&ch[0].ao.shu[0].rk[1].selph_dq[3], + (0x7 << 16) | (0x7 << 20) | (0x7 << 24) | (0x7 << 28), + (0x4 << 16) | (0x4 << 20) | (0x4 << 24) | (0x4 << 28)); + clrsetbits_le32(&ch[0].ao.shu[0].dqsg_retry, + (0x1 << 2) | (0xf << 8) | (0x1 << 14) | (0x3 << 24), + (0x1 << 2) | (0x5 << 8) | (0x0 << 14) | (0x1 << 24)); + + if (get_cbt_mode(params) == CBT_BYTE_MODE1) { + setbits_le32(&ch[0].phy.shu[0].b[0].dq[7], (0x1 << 12)); + setbits_le32(&ch[0].phy.shu[0].b[1].dq[7], (0x1 << 12)); + } else { + setbits_le32(&ch[0].phy.shu[0].b[0].dq[7], + (0x1 << 12) | (0x1 << 13)); + setbits_le32(&ch[0].phy.shu[0].b[1].dq[7], + (0x1 << 12) | (0x1 << 13)); + } + + clrbits_le32(&ch[0].ao.shu[0].dqs2dq_tx, (0x1f << 0)); + update_initial_settings(); + + clrbits_le32(&ch[0].ao.test2_4, (0x1 << 17)); + clrsetbits_le32(&ch[0].ao.shu[0].conf[3], (0x1ff << 0), (0x5 << 0)); + delay(1); + + setbits_le32(&ch[0].ao.refctrl0, (0x1 << 17) | (0x1 << 18)); + setbits_le32(&ch[0].ao.shuctrl2, (0x1 << 24) | (0x1 << 25)); + setbits_le32(&ch[0].ao.refctrl0, (0x1 << 29)); + setbits_le32(&ch[0].ao.dramctrl, (0x1 << 26)); + clrsetbits_le32(&ch[0].ao.dummy_rd, + (0x1 << 4) | (0x1 << 11) | (0x1 << 13) | + (0x1 << 14) | (0x3 << 16) | (0x1 << 22), + (0x1 << 4) | (0x1 << 11) | (0x1 << 13) | + (0x1 << 14) | (0x2 << 16) | (0x1 << 22)); + clrsetbits_le32(&ch[0].ao.test2_4, (0x7 << 28), (0x4 << 28)); + clrbits_le32(&ch[0].ao.dramctrl, (0x1 << 0)); + + udelay(1); + + dramc_broadcast_onoff(DRAMC_BROADCAST_OFF); + + clrsetbits_le32(&ch[0].ao.shuctrl, + (0x1 << 5)|(0x1 << 17), (0x0 << 5)|(0x1 << 17)); + setbits_le32(&ch[0].ao.shuctrl2, (0x1 << 12)); + + clrsetbits_le32(&ch[1].ao.shuctrl, + (0x1 << 5)|(0x1 << 17), (0x1 << 5)|(0x0 << 17)); + clrbits_le32(&ch[1].ao.shuctrl2, (0x1 << 12)); + + s8 clkDelay = params->clk_delay; + s8 dqsDelay[CHANNEL_NUM] = {params->dqs_delay[CHANNEL_A], + params->dqs_delay[CHANNEL_B]}; + dramc_dbg("%s param: clkdelay:0x%x," + " dqsDelay[0]:0x%x, dqsDelay[1]:0x%x\n", __func__, + clkDelay, dqsDelay[0], dqsDelay[1]); + + dramc_duty_calibration(CHANNEL_A, clkDelay, dqsDelay[CHANNEL_A]); + dramc_duty_calibration(CHANNEL_B, clkDelay, dqsDelay[CHANNEL_B]); + + dramc_mode_reg_init(); +} + +void dramc_ac_timing_optimize(void) +{ + u8 chn; + dramc_dbg("[ACTiming Optimize] For MR8[5:2] = 4 sample only\n"); + dramc_dbg("16Gb per die (8Gb per channel)\n"); + + for (chn = 0; chn < CHANNEL_NUM; chn++) { + clrsetbits_le32(&ch[chn].ao.shu[0].actim[3], + (0xff << 16), (0x64 << 16)); + clrbits_le32(&ch[chn].ao.shu[0].ac_time_05t, (0x1 << 2)); + clrsetbits_le32(&ch[chn].ao.shu[0].actim[4], + (0x3ff << 0), (0x77 << 0)); + } +} + +static void ddr_update_ac_timing(void) +{ + u32 temp; + + for (u8 chn = 0; chn < CHANNEL_NUM; chn++) { + clrsetbits_le32(&ch[chn].ao.shu[0].actim[0], + (0xf << 24) | (0x7 << 16) | (0x1f << 8) | (0xf << 0), + (0x6 << 24) | (0x2 << 16) | (0xc << 8) | (0x7 << 0)); + clrsetbits_le32(&ch[chn].ao.shu[0].actim[1], + (0x1f << 24) | (0xf << 16) | (0xf << 8) | (0x7 << 0), + (0x10 << 24) | (0x8 << 16) | (0x5 << 8) | (0x1 << 0)); + clrsetbits_le32(&ch[chn].ao.shu[0].actim[2], + (0x1f << 24) | (0xf << 16) | (0x7 << 8) | (0x7 << 0), + (0x7 << 24) | (0x7 << 16) | (0x2 << 8) | (0x1 << 0)); + clrsetbits_le32(&ch[chn].ao.shu[0].actim[3], + (0xff << 16) | (0xff << 24) | (0xff << 0), + (0x64 << 16) | (0x61 << 24) | (0x2c << 0)); + clrsetbits_le32(&ch[chn].ao.shu[0].actim[4], + (0xff << 24) | (0xff << 16) | (0x3ff << 0), + (0x22 << 24) | (0x65 << 16) | (0x77 << 0)); + clrsetbits_le32(&ch[chn].ao.shu[0].actim[5], + (0xf << 24) | (0x1f << 8) | (0x1f << 0), + (0xa << 24) | (0xc << 8) | (0xb << 0)); + clrsetbits_le32(&ch[chn].ao.shu[0].actim_xrt, + (0xf << 24) | (0x7 << 16) | (0xf << 8) | (0x1f << 0), + (0x5 << 24) | (0x3 << 16) | (0x6 << 8) | (0x9 << 0)); + clrsetbits_le32(&ch[chn].ao.shu[0].ac_time_05t, + (0x1 << 25) | (0x0 << 24) | (0x1 << 16) | (0x0 << 15)| + (0x1 << 13) | (0x1 << 12) | (0x1 << 10) | (0x1 << 9) | + (0x1 << 8) | (0x1 << 7) | (0x1 << 6) | (0x1 << 5) | + (0x1 << 4) | (0x1 << 2) | (0x1 << 1) | (0x1 << 0), + (0x0 << 25) | (0x0 << 24) | (0x1 << 16) | (0x0 << 15) | + (0x0 << 13) | (0x0 << 12) | (0x1 << 10) | (0x1 << 9) | + (0x0 << 8) | (0x1 << 7) | (0x1 << 6) | (0x1 << 5) | + (0x0 << 4) | (0x0 << 2) | (0x0 << 1) | (0x1 << 0)); + clrsetbits_le32(&ch[chn].ao.catraining1, + (0xff << 24) | (0xf << 20), (0xb << 24) | (0x0 << 20)); + + /* DQSINCTL related */ + clrsetbits_le32(&ch[chn].ao.shu[0].rk[0].dqsctl, + (0xf << 0), (0x4 << 0)); + clrsetbits_le32(&ch[chn].ao.shu[0].rk[1].dqsctl, + (0xf << 0), (0x4 << 0)); + clrsetbits_le32(&ch[chn].ao.shu[0].odtctrl, + (0xf << 4), (0x4 << 4)); + + /* DATLAT related, tREFBW */ + clrsetbits_le32(&ch[chn].ao.shu[0].conf[1], + (0x1f << 0) | (0x1f << 8) | + (0x1f << 26) | (0x3ff << 16), + (0xf << 0) | (0xd << 8) | (0xd << 26) | (0x0 << 16)); + clrsetbits_le32(&ch[chn].ao.shu[0].conf[2], + (0xff << 8), (0x64 << 8)); + clrsetbits_le32(&ch[chn].ao.shu[0].scintv, + (0x1f << 13) | (0x1f << 6), (0xf << 13) | (0xc << 6)); + + /* CKEPRD - CKE pulse width */ + clrsetbits_le32(&ch[chn].ao.shu[0].ckectrl, + (0x7 << 20), (0x2 << 20)); + + /* CKELCKCNT: Valid clock requirement after CKE input low */ + clrsetbits_le32(&ch[chn].ao.ckectrl, (0x7 << 24), (0x0 << 24)); + + /* Ininital setting values are the same, + * RANKINCTL_RXDLY = RANKINCTL = RANKINCTL_ROOT1 + * XRTR2R setting will be updated in RxdqsGatingPostProcess */ + temp = (read32(&ch[chn].ao.shu[0].rankctl) & 0x00f00000) >> 20; + clrsetbits_le32(&ch[chn].ao.shu[0].rankctl, + (0xf << 0), (temp << 0)); + + u8 u1ROOT = 0, u1TXRANKINCTL = 1, u1TXDLY = 2; + clrsetbits_le32(&ch[chn].ao.shu[0].rankctl, + (0xf << 16) | (0xf << 12) | (0xf << 8), + (u1ROOT << 16) | (u1TXRANKINCTL << 12) | + (u1TXDLY << 8)); + } +} + +void dramc_init(const struct sdram_params *params) +{ + u8 dram_t = 3; + u8 dram_cbt_mode, dram_cbt_mode_r0, dram_cbt_mode_r1; + + dramc_setting(params); + + ddr_update_ac_timing(); + + clrsetbits_le32(&ch[0].ao.arbctl, (0x3 << 10), (dram_t << 10)); + + dram_cbt_mode = get_cbt_mode(params); + dram_cbt_mode_r0 = dram_cbt_mode_r1 = dram_cbt_mode; + + clrsetbits_le32(&ch[0].ao.rstmask, (0x3 << 13), dram_cbt_mode); + + clrsetbits_le32(&ch[0].ao.arbctl, (0x1 << 13), + dram_cbt_mode_r0 | dram_cbt_mode_r1); +} diff --git a/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c b/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c new file mode 100644 index 0000000..f08a659 --- /dev/null +++ b/src/soc/mediatek/mt8183/dramc_pi_calibration_api.c @@ -0,0 +1,2626 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/io.h> +#include <soc/dramc_register.h> +#include <soc/dramc_pi_api.h> +#include <soc/emi.h> +#include <delay.h> +#include <soc/infracfg.h> + +#define TX_DQ_COARSE_TUNE_TO_FINE_TUNE_TAP 64 +#define IMP_LP4X_TERM_VREF_SEL 0x1b +#define IMP_DRVP_LP4X_UNTERM_VREF_SEL 0x1a +#define IMP_DRVN_LP4X_UNTERM_VREF_SEL 0x16 +#define IMP_TRACK_LP4X_UNTERM_VREF_SEL 0x1a + +enum { + DQ_DIV_SHIFT = 3, + DQ_DIV_MASK = BIT(DQ_DIV_SHIFT) - 1, + OEN_SHIFT = 16, +}; + +enum { + RX_VREF_BEGIN = 0, + RX_VREF_END = 12, + RX_VREF_STEP = 0x1, + TX_VREF_BEGIN = 8, + TX_VREF_END = 18, + TX_VREF_STEP = 1, +}; + +enum { + FIRST_DQ_DELAY = 0, + FIRST_DQS_DELAY = -27, + MAX_DQDLY_TAPS = 16, + MAX_RX_DQDLY_TAPS = 63, + MAX_TX_DQDLY_TAPS = 200, + MAX_TX_DQSDLY_TAPS = 63, + MAX_RX_DQSDLY_TAPS = 26 +}; + +enum { + RX_WIN = 0, + STAGE_SETUP = 0, + STAGE_HOLD = 1, + STAGE_SETUP_RX_WIN = STAGE_SETUP | RX_WIN << 1, + STAGE_HOLD_RX_WIN = STAGE_HOLD | RX_WIN << 1, + STAGE_PRE_HOLD_RX_WIN, + TX_WIN_MOVE_DQ_ONLY, + TX_WIN_MOVE_DQ_DQM, +}; + +enum { + RX_DQ = 0, + RX_DQM, + RX_DQS, + TX_DQ, + TX_DQS, + TX_DQM +}; + +struct dqs_perbit_dly { + u8 vref; + s16 first_dqdly_pass; + s16 last_dqdly_pass; + s16 first_dqsdly_pass; + s16 last_dqsdly_pass; + s16 best_first_dqdly_pass; + s16 best_last_dqdly_pass; + s16 best_first_dqsdly_pass; + s16 best_last_dqsdly_pass; + s16 best_dqdly; + s16 best_dqsdly; +}; + +struct tx_dly_coarse_fine_tune { + u8 fine_tune; + u8 coarse_tune_large; + u8 coarse_tune_small; + u8 coarse_tune_large_oen; + u8 coarse_tune_small_oen; +}; + +struct per_byte_dly { + u16 max_center; + u16 min_center; + u16 final_dly; +}; + +static void auto_refresh_switch(u8 chn, u8 option) +{ + if (option == ENABLE) { + /* enable autorefresh */ + clrbits_le32(&ch[chn].ao.refctrl0, 1 << REFCTRL0_REFDIS_SHIFT); + } else { + /* disable autorefresh */ + setbits_le32(&ch[chn].ao.refctrl0, 1 << REFCTRL0_REFDIS_SHIFT); + + /* because HW will actually disable autorefresh + * after refresh_queue empty, we need to wait quene empty */ + udelay(((read32(&ch[chn].nao.misc_statusa) & + MISC_STATUSA_REFRESH_QUEUE_CNT_MASK) >> + MISC_STATUSA_REFRESH_QUEUE_CNT_SHIFT)*4); + } +} + +static void dramc_rank_swap(u8 chn, u8 rank) +{ + u8 multi_rank = 1; + + dramc_dbg("[RankSwap] (Multi %d), Rank %d\n", multi_rank, rank); + + clrsetbits_le32(&ch[chn].ao.rkcfg, + RKCFG_RKMODE_MASK | 1 << RKCFG_RKSWAP_SHIFT | RKCFG_TXRANK_MASK, + (multi_rank << RKCFG_RKMODE_SHIFT) | + (rank << RKCFG_RKSWAP_SHIFT) | (rank << RKCFG_TXRANK_SHIFT)); + + /* TXRANK should be set before TXRANKFIX */ + clrsetbits_le32(&ch[chn].ao.rkcfg, + 1 << RKCFG_TXRANKFIX_SHIFT, rank << RKCFG_TXRANKFIX_SHIFT); +} + +static void move_dramc_dq_common(uint32_t *reg_0p5t, uint32_t *reg_2t, + u8 shift, s8 shift_coarse_tune) +{ + s32 tmp_0p5t, tmp_2t; + s32 sum = (((read32(reg_2t) >> shift) & DQ_DIV_MASK) << DQ_DIV_SHIFT) + + ((read32(reg_0p5t) >> shift) & DQ_DIV_MASK) + + shift_coarse_tune; + + if (sum < 0) + sum = 0; + + tmp_0p5t = sum & DQ_DIV_MASK; + tmp_2t = sum >> DQ_DIV_SHIFT; + + clrsetbits_le32(reg_0p5t, DQ_DIV_MASK << shift, tmp_0p5t << shift); + clrsetbits_le32(reg_2t, DQ_DIV_MASK << shift, tmp_2t << shift); +} + +static void move_dramc_tx_dqs(u8 chn, u8 byte_idx, s8 shift_coarse_tune) +{ + move_dramc_dq_common(&ch[chn].ao.shu[0].selph_dqs1, + &ch[chn].ao.shu[0].selph_dqs0, + byte_idx * 4, shift_coarse_tune); +} + +static void move_dramc_tx_dqs_oen(u8 chn, u8 byte_idx, + s8 shift_coarse_tune) +{ + move_dramc_dq_common(&ch[chn].ao.shu[0].selph_dqs1, + &ch[chn].ao.shu[0].selph_dqs0, + (byte_idx * 4) + OEN_SHIFT, shift_coarse_tune); +} + +static void move_dramc_tx_dq(u8 chn, u8 rank, u8 byte_idx, s8 shift_coarse_tune) +{ + move_dramc_dq_common(&ch[chn].ao.shu[0].rk[rank].selph_dq[3], + &ch[chn].ao.shu[0].rk[rank].selph_dq[1], + byte_idx * 4, shift_coarse_tune); + + move_dramc_dq_common(&ch[chn].ao.shu[0].rk[rank].selph_dq[2], + &ch[chn].ao.shu[0].rk[rank].selph_dq[0], + byte_idx * 4, shift_coarse_tune); +} + +static void move_dramc_tx_dq_oen(u8 chn, u8 rank, + u8 byte_idx, s8 shift_coarse_tune) +{ + move_dramc_dq_common(&ch[chn].ao.shu[0].rk[rank].selph_dq[3], + &ch[chn].ao.shu[0].rk[rank].selph_dq[1], + (byte_idx * 4) + OEN_SHIFT, shift_coarse_tune); + + move_dramc_dq_common(&ch[chn].ao.shu[0].rk[rank].selph_dq[2], + &ch[chn].ao.shu[0].rk[rank].selph_dq[0], + (byte_idx * 4) + OEN_SHIFT, shift_coarse_tune); +} + +static void write_leveling_move_dqs_instead_of_clk(u8 chn) +{ + for (u8 byte_idx = 0; byte_idx < DQS_NUMBER; byte_idx++) { + move_dramc_tx_dqs(chn, byte_idx, -1); + move_dramc_tx_dqs_oen(chn, byte_idx, -1); + + for (u8 i = RANK_0; i < RANK_MAX; i++) { + move_dramc_tx_dq(chn, i, byte_idx, -1); + move_dramc_tx_dq_oen(chn, i, byte_idx, -1); + } + } +} + +void dramc_mode_reg_write(u8 chn, u8 mr_idx, u8 value) +{ + u32 rank = 0; + u32 u4reg_024; + + u4reg_024 = read32(&ch[chn].ao.ckectrl); + + cke_fix_onoff(CKE_FIXON, chn); + + clrsetbits_le32(&ch[chn].ao.mrs, + MRS_MRSMA_MASK, mr_idx << MRS_MRSMA_SHIFT); + clrsetbits_le32(&ch[chn].ao.mrs, + MRS_MRSOP_MASK, value << MRS_MRSOP_SHIFT); + + setbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_MRWEN_SHIFT); + + while ((read32(&ch[chn].nao.spcmdresp) & 1) == 0) { + dramc_dbg("wait MRW command fired\n"); + udelay(1); + } + + clrbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_MRWEN_SHIFT); + setbits_le32(&ch[chn].ao.ckectrl, u4reg_024); + + rank = (read32(&ch[chn].ao.mrs) & MRS_MRSRK_MASK) >> + MRS_MRSRK_SHIFT; + + dramc_dbg("Write Rank%d MR%d =0x%x\n", rank, mr_idx, value); +} + +void dramc_mode_reg_write_by_rank(u8 chn, u8 rank, + u8 mr_idx, u8 value) +{ + u32 u4RabnkBackup; + + u4RabnkBackup = (read32(&ch[chn].ao.mrs) & MRS_MRSRK_MASK) >> 24; + + clrsetbits_le32(&ch[chn].ao.mrs, + MRS_MRSRK_MASK, rank << MRS_MRSRK_SHIFT); + dramc_mode_reg_write(chn, mr_idx, value); + + clrsetbits_le32(&ch[chn].ao.mrs, + MRS_MRSRK_MASK, u4RabnkBackup << MRS_MRSRK_SHIFT); +} + +static void dramc_write_leveling(u8 chn, u8 rank, + const struct sdram_params *params) +{ + s32 wrlevel_dq_delay[DQS_NUMBER]; + s32 wrlevel_dqs_final_delay[DQS_NUMBER]; + s32 clock_delay_max = 0; + + dramc_show("chn:%d, rank:%d params write level:0x%x, 0x%x\n", + chn, rank, params->wr_level[chn][rank][0], + params->wr_level[chn][rank][1]); + + wrlevel_dqs_final_delay[0] = params->wr_level[chn][rank][0]; + wrlevel_dqs_final_delay[1] = params->wr_level[chn][rank][1]; + + dramc_rank_swap(chn, rank); + + if (rank == RANK_0) + write_leveling_move_dqs_instead_of_clk(chn); + + dramc_dbg("No need to update CA/CS dly (CLK dly smaller than CA training)\n"); + + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].ca_cmd[9], + SHU1_CA_CMD9_RG_RK_ARFINE_TUNE_CLK_MASK, + clock_delay_max << SHU1_CA_CMD9_RG_RK_ARFINE_TUNE_CLK_SHIFT); + + dramc_dbg("Final Clk output dly = %d\n", clock_delay_max); + + for (size_t i = 0; i < DQS_NUMBER; i++) { + dramc_dbg("DQS%zd dly: %d\n", i, wrlevel_dqs_final_delay[i]); + } + + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[7], + SHU1_B0_DQ7_RK_ARFINE_TUNE_PBYTE_B0_MASK, + wrlevel_dqs_final_delay[0] << + SHU1_B0_DQ7_RK_ARFINE_TUNE_PBYTE_B0_SHIFT); + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[7], + SHU1_B1_DQ7_RK_ARFINE_TUNE_PBYTE_B1_MASK, + wrlevel_dqs_final_delay[1] << + SHU1_B1_DQ7_RK_ARFINE_TUNE_PBYTE_B1_SHIFT); + + for (u8 i = 0; i < DQS_NUMBER; i++) { + wrlevel_dq_delay[i] = wrlevel_dqs_final_delay[i] + 0x10; + if (wrlevel_dq_delay[i] >= 0x40) { + wrlevel_dq_delay[i] -= 0x40; + move_dramc_tx_dq(chn, rank, i, 2); + move_dramc_tx_dq_oen(chn, rank, i, 2); + } + } + dramc_show("chn:%d, rank:%d, dq_delay: 0x%x, 0x%x\n", + chn, rank, wrlevel_dq_delay[0], wrlevel_dq_delay[1]); + + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[7], + SHU1_B0_DQ7_RK_ARFINE_TUNE_DQM_B0_MASK | + SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_MASK, + (wrlevel_dq_delay[0] << + SHU1_B0_DQ7_RK_ARFINE_TUNE_DQM_B0_SHIFT) | + (wrlevel_dq_delay[0] << + SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_SHIFT)); + + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[7], + SHU1_B1_DQ7_RK_ARFINE_TUNE_DQM_B1_MASK | + SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_MASK, + (wrlevel_dq_delay[1] << + SHU1_B1_DQ7_RK_ARFINE_TUNE_DQM_B1_SHIFT) | + (wrlevel_dq_delay[1] << + SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_SHIFT)); + + dramc_rank_swap(chn, RANK_0); +} + +static void cmd_bus_training(u8 chn, u8 rank, + const struct sdram_params *params) +{ + u32 cbt_cs, i_mr12_value; + + cbt_cs = params->cbt_cs[chn][rank]; + i_mr12_value = params->cbt_mr12[chn][rank]; + + dramc_dbg("start chn:%d, rank:%d, " + "cbt_cs:0x%x, mr12_value:0x%x\n", + chn, rank, cbt_cs, i_mr12_value); + + /* cbt_adjust_cs */ + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].ca_cmd[9], + SHU1_CA_CMD9_RG_RK_ARFINE_TUNE_CS_MASK, + cbt_cs << 0); + + /* cbt_set_vref */ + dramc_mode_reg_write_by_rank(chn, rank, 12, i_mr12_value); +} + +void dramc_gating_mode(u8 chn, u8 mode) +{ + u8 VrefSel = 0, BurstE2 = 0; + if (mode == 0) { + VrefSel = 0; + BurstE2 = 0; + } else { + VrefSel = 2; + BurstE2 = 1; + } + + clrsetbits_le32(&ch[chn].ao.stbcal1, (0x1 << 5), (BurstE2 << 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), (VrefSel << 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)); + udelay(1); + setbits_le32(&ch[chn].phy.b[b].dq[9], (0x1 << 4) | (0x1 << 0)); + } +} + +static void rx_dqs_isi_pulse_cg_en(u8 chn) +{ + dramc_dbg("CH %d RX DQS ISI pulse CG: enable\n", chn); + + setbits_le32(&ch[chn].phy.b[0].dq[6], + 1 << B0_DQ6_RG_RX_ARDQ_RPRE_TOG_EN_B0_SHIFT); + setbits_le32(&ch[chn].phy.b[1].dq[6], + 1 << B1_DQ6_RG_RX_ARDQ_RPRE_TOG_EN_B1_SHIFT); +} + +static void rx_dqs_isi_pulse_cg_dis(u8 chn) +{ + dramc_dbg("CH %d RX DQS ISI pulse CG: disable\n", chn); + + clrbits_le32(&ch[chn].phy.b[0].dq[6], + 1 << B0_DQ6_RG_RX_ARDQ_RPRE_TOG_EN_B0_SHIFT); + clrbits_le32(&ch[chn].phy.b[1].dq[6], + 1 << B1_DQ6_RG_RX_ARDQ_RPRE_TOG_EN_B1_SHIFT); +} + +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 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) +{ + u8 dqs; + u32 pass_byte_count = 0, current_pass = 0; + 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]; + + u32 coarse_start = 18; + u32 coarse_end = coarse_start + 24; + + for (dqs = 0; dqs < DQS_NUMBER; dqs++) { + if (pass_byte_count & (1 << dqs)) + continue; + + 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]; + + current_pass = 0; + + if ((dqs_result_r == 0) && (dqs_result_f == 0) && + (debug_cnt_perbyte == GATING_GOLDEND_DQSCNT)) + current_pass = 1; + + if (current_pass) { + 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 = coarse_end; + } + } + } +} + +static void find_dly_tune(u8 chn, u8 dly_coarse_large, u8 dly_coarse_0p5t, + u8 dly_fine_xt, u8 *dqs_cnt1, u8 *dqs_cnt2, u8 *dqs_high, + u8 *dly_coarse_large_cnt, u8 *dly_coarse_0p5t_cnt, + u8 *dly_fine_tune_cnt, u8 *dqs_transition) +{ + for (u8 dqs = 0; dqs < DQS_NUMBER; dqs++) { + if (dqs == 0) { + dqs_cnt1[0] = + (read32(&ch[chn].phy_nao.misc_phy_stben_b0) + >> 16) & 1; + dqs_cnt2[0] = + (read32(&ch[chn].phy_nao.misc_phy_stben_b0) + >> 17) & 1; + } else { + dqs_cnt1[1] = + (read32(&ch[chn].phy_nao.misc_phy_stben_b1) + >> 16) & 1; + dqs_cnt2[1] = + (read32(&ch[chn].phy_nao.misc_phy_stben_b1) + >> 17) & 1; + } + + if ((dqs_cnt1[dqs] == 1) && (dqs_cnt2[dqs] == 1)) + dqs_high[dqs]++; + + if (dqs_high[dqs] * DQS_GW_FINE_STEP <= 16) + continue; + + if ((dqs_cnt1[dqs] == 1) && (dqs_cnt2[dqs] == 1)) { + 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_transition[dqs] = 1; + } else if (((dqs_cnt1[dqs] == 1) && (dqs_cnt2[dqs] == 0)) || + ((dqs_cnt1[dqs] == 0) && (dqs_cnt2[dqs] == 1))) { + if (dqs_transition[dqs] == 1) + dramc_dbg("[Byte %d] cnt1/cnt2 falling Transition" + " (%d, %d, %d)\n", + dqs, dly_coarse_large_cnt[dqs], + dly_coarse_0p5t_cnt[dqs], + dly_fine_tune_cnt[dqs]); + + dqs_transition[dqs]++; + } else if ((dqs_cnt1[dqs] == 0) && (dqs_cnt2[dqs] == 0)) { + dramc_dbg("[Byte %d] cnt1/cnt2 Transition tap number (%d)\n", + dqs, dqs_transition[dqs]); + dqs_high[dqs] = 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 = 8, coarse_end = 8; + u32 debug_cnt[DQS_NUMBER]; + + u8 dqs_cnt1[DQS_NUMBER], dqs_cnt2[DQS_NUMBER], + 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 *u4RegBackup[] = { + &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], + }; + + save_restore_multi_reg(SAVE_VALUE, + u4RegBackup, ARRAY_SIZE(u4RegBackup)); + + rx_dqs_isi_pulse_cg_dis(chn); + 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); + dramc_engine2_init(chn, rank, + DEFAULT_TEST2_1_CAL, 0xaa000000 | GATING_PATTERN_NUM, + TEST_AUDIO_PATTERN, 0); + for (dqs = 0; dqs < DQS_NUMBER; dqs++) { + pass_begin[dqs] = 0; + pass_count[dqs] = 0; + dqs_cnt1[dqs] = 0; + dqs_cnt2[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"); + + coarse_start = 18; + coarse_end = coarse_start + 24; + + 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_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, TEST_AUDIO_PATTERN); + + 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_gating_mode(chn, 1); + dramc_engine2_run(chn, + TE_OP_READ_CHECK, TEST_AUDIO_PATTERN); + + find_dly_tune(chn, dly_coarse_large, dly_coarse_0p5t, + dly_fine_xt, &dqs_cnt1[0], &dqs_cnt2[0], + &dqs_high[0], &dly_coarse_large_cnt[0], + &dly_coarse_0p5t_cnt[0], + &dly_fine_tune_cnt[0], &dqs_transition[0]); + + 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(" |"); + for (dqs = 0; dqs < DQS_NUMBER; dqs++) + dramc_show("(%d %d)", + dqs_cnt1[dqs], dqs_cnt2[dqs]); + + 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); + + 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("\nbest 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("\nbest 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]); + + save_restore_multi_reg(RESTORE_VALUE, + u4RegBackup, ARRAY_SIZE(u4RegBackup)); + + dramc_mode_reg_write_by_rank(chn, rank, 0x1, mr1_value[1] & 0x7f); + + rx_dqs_isi_pulse_cg_en(chn); + + 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("\nbest 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); + dramc_dbg("[dramc_rx_dqs_gating_cal] Done\n\n"); +} + +static void dramc_rx_dqs_gating_post_process(u8 chn) +{ + u8 dqs, rank_rx_dvs, dbi_r_on = 0; + u8 rank, rank_max, rank_cur = 0; + s8 change_dqsinctl; + u32 read_dqsinctl, read_rodt; + u32 rankinctl_root, xrtr2r, reg_tx_dly_dqsgated_min = 0; + 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]; + + reg_tx_dly_dqsgated_min = 3; + rank_rx_dvs = reg_tx_dly_dqsgated_min - 1; + + clrsetbits_le32(&ch[chn].phy.shu[0].b[0].dq[7], + SHU1_B0_DQ7_R_DMRANKRXDVS_B0_MASK, + rank_rx_dvs << SHU1_B0_DQ7_R_DMRANKRXDVS_B0_SHIFT); + clrsetbits_le32(&ch[chn].phy.shu[0].b[1].dq[7], + SHU1_B1_DQ7_R_DMRANKRXDVS_B1_MASK, + rank_rx_dvs << SHU1_B1_DQ7_R_DMRANKRXDVS_B1_SHIFT); + + if (((read32(&ch[chn].ao.rstmask)>> + RSTMASK_RSV_DRAM_SUPPORT_RANK_NUM_SHIFT) & 1) == 0) + rank_max = RANK_MAX; + else + rank_max = RANK_1; + + for (rank = 0; rank < rank_max; rank++) { + for (dqs = 0; dqs < DQS_NUMBER; dqs++) { + best_coarse_tune2t[rank][dqs] = + (read32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg0) >> + (dqs * 8)) & + SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_MASK; + best_coarse_tune2t_p1[rank][dqs] = + ((read32(&ch[chn].ao.shu[0].rk[rank].selph_dqsg0) + >> (dqs * 8)) & + SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_MASK) >> + SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_SHIFT; + dramc_dbg("\nrank%d best DQS%d dly(2T, (P1)2T) = (%d, %d)\n", + (u32) rank, (u32) dqs, + (u32) best_coarse_tune2t[rank][dqs], + (u32) best_coarse_tune2t_p1[rank][dqs]); + + tx_dly_dqs_gated = best_coarse_tune2t[rank][dqs]; + if (tx_dly_dqs_gated < txdly_cal_min) + txdly_cal_min = tx_dly_dqs_gated; + + tx_dly_dqs_gated = best_coarse_tune2t_p1[rank][dqs]; + if (tx_dly_dqs_gated > txdly_cal_max) + txdly_cal_max = tx_dly_dqs_gated; + } + } + + change_dqsinctl = reg_tx_dly_dqsgated_min - txdly_cal_min; + + dramc_dbg + ("ChangeDQSINCTL %d, tx_dly_dqsgated_min %d, txdly_cal_min %d\n", + change_dqsinctl, reg_tx_dly_dqsgated_min, txdly_cal_min); + + if (change_dqsinctl != 0) { + txdly_cal_min += change_dqsinctl; + txdly_cal_max += change_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] += change_dqsinctl; + best_coarse_tune2t_p1[rank][dqs] += change_dqsinctl; + + dramc_dbg("best DQS%d dly(2T) = (%d)\n", dqs, + best_coarse_tune2t[rank][dqs]); + } + + for (dqs = 0; dqs < DQS_NUMBER; dqs++) { + dramc_dbg("best DQS%d P1 dly(2T) = (%d)\n", + dqs, + best_coarse_tune2t_p1[rank][dqs]); + } + } + + for (rank = 0; rank < rank_max; rank++) { + 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[rank_cur].dqsctl) & + SHURK_DQSCTL_DQSINCTL_MASK; + read_dqsinctl -= change_dqsinctl; + + if (dbi_r_on) { + read_dqsinctl++; + read_rodt = + (read32(&ch[chn].ao.shu[0].odtctrl) & + SHU_ODTCTRL_RODT_MASK) >> SHU_ODTCTRL_RODT_SHIFT; + clrsetbits_le32(&ch[chn].ao.shu[0].odtctrl, + SHU_ODTCTRL_RODT_MASK, + (read_rodt + 1) << SHU_ODTCTRL_RODT_SHIFT); + } + + 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, + read_dqsinctl << SHU_RANKCTL_RANKINCTL_PHY_SHIFT); + clrsetbits_le32(&ch[chn].ao.shu[0].rankctl, + SHU_RANKCTL_RANKINCTL_MASK, + rankinctl_root << SHU_RANKCTL_RANKINCTL_SHIFT); + clrsetbits_le32(&ch[chn].ao.shu[0].rankctl, + SHU_RANKCTL_RANKINCTL_ROOT1_MASK, + rankinctl_root << SHU_RANKCTL_RANKINCTL_ROOT1_SHIFT); + + xrtr2r = 8 + txdly_cal_max + 1; + if (xrtr2r > 12) { + xrtr2r = 12; + dramc_dbg("XRTR2R > 12, Max value is 12\n"); + } + + clrsetbits_le32(&ch[chn].ao.shu[0].actim_xrt, + SHU_ACTIM_XRT_XRTR2R_MASK, + xrtr2r << SHU_ACTIM_XRT_XRTR2R_SHIFT); + + dramc_dbg("TX_dly_DQSgated check: min %d max %d, ChangeDQSINCTL=%d\n", + txdly_cal_min, txdly_cal_max, change_dqsinctl); + dramc_dbg("DQSINCTL=%d, RANKINCTL=%d, XRTR2R=%d\n", + read_dqsinctl, rankinctl_root, xrtr2r); +} + +static void dramc_rd_dqc_init(u8 chn, u8 rank) +{ + u8 *lpddr_phy_mapping; + u16 temp_value = 0; + u8 mr15_golden_value = 0; + u8 mr20_golden_value = 0; + int i; + const u8 LPDDR4_PHY_Mapping_POP[CHANNEL_NUM][16] = { + /* CHA */ + { + 1, 0, 2, 4, 3, 7, 5, 6, + 9, 8, 12, 11, 10, 15, 13, 14 + }, + /* CHB */ + { + 0, 1, 5, 6, 3, 7, 4, 2, + 9, 8, 12, 15, 11, 14, 13, 10 + } + }; + + clrbits_le32(&ch[chn].phy.shu[0].b[0].dq[7], + 0x1 << SHU1_B0_DQ7_R_DMDQMDBI_SHU_B0_SHIFT); + clrbits_le32(&ch[chn].phy.shu[0].b[1].dq[7], + 0x1 << SHU1_B1_DQ7_R_DMDQMDBI_SHU_B1_SHIFT); + + if(rank == RANK_0) + clrsetbits_le32(&ch[chn].ao.mrs, + MRS_MRSRK_MASK, 0 << MRS_MRSRK_SHIFT); + else + clrsetbits_le32(&ch[chn].ao.mrs, + MRS_MRSRK_MASK, 1 << MRS_MRSRK_SHIFT); + setbits_le32(&ch[chn].ao.mpc_option, + (0x1 << MPC_OPTION_MPCRKEN_SHIFT)); + + lpddr_phy_mapping = (u8 *)LPDDR4_PHY_Mapping_POP[chn]; + for (i = 0; i < 16; i++) + temp_value |= ((0x5555 >> i) & 0x1) << lpddr_phy_mapping[i]; + + mr15_golden_value = (u8) temp_value & 0xff; + mr20_golden_value = (u8) (temp_value >> 8) & 0xff; + + clrsetbits_le32(&ch[chn].ao.mr_golden, + MR_GOLDEN_MR15_GOLDEN_MASK | MR_GOLDEN_MR20_GOLDEN_MASK, + mr15_golden_value << 8 | mr20_golden_value); +} + +static u32 dramc_rd_dqc_run(u8 chn) +{ + u16 timeout_cnt = 100; + u8 response; + u32 result; + + setbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_RDDQCEN_SHIFT); + setbits_le32(&ch[chn].ao.spcmdctrl, 1 << SPCMDCTRL_RDDQCDIS_SHIFT); + + do { + response = + read32(&ch[chn].nao.spcmdresp) + & (0x1 << SPCMDRESP_RDDQC_RESPONSE_SHIFT); + timeout_cnt--; + udelay(1); + } while ((response == 0) && (timeout_cnt > 0)); + + if (timeout_cnt == 0) + dramc_dbg("[RxWinRDDQC] Resp fail (time out)\n"); + + result = read32(&ch[chn].nao.rdqc_cmp); + clrbits_le32(&ch[chn].ao.spcmd, 1 << SPCMD_RDDQCEN_SHIFT); + clrbits_le32(&ch[chn].ao.spcmdctrl, 1 << SPCMDCTRL_RDDQCDIS_SHIFT); + + return result; +} + +static void dramc_rd_dqc_end(u8 chn) +{ + clrsetbits_le32(&ch[chn].ao.mrs, MRS_MRSRK_MASK, 0 << MRS_MRSRK_SHIFT); +} + +static void dramc_vref_enable(u8 chn) +{ + setbits_le32(&ch[chn].phy.b[0].dq[5], + 0x1 << B0_DQ5_RG_RX_ARDQ_VREF_EN_B0_SHIFT); + setbits_le32(&ch[chn].phy.b[1].dq[5], + 0x1 << B1_DQ5_RG_RX_ARDQ_VREF_EN_B1_SHIFT); +} + +static void dramc_set_rx_vref(u8 chn, u8 value) +{ + clrsetbits_le32(&ch[chn].phy.shu[0].b[0].dq[5], + SHU1_B0_DQ5_RG_RX_ARDQ_VREF_SEL_B0_MASK, + value << SHU1_B0_DQ5_RG_RX_ARDQ_VREF_SEL_B0_SHIFT); + clrsetbits_le32(&ch[chn].phy.shu[0].b[1].dq[5], + SHU1_B1_DQ5_RG_RX_ARDQ_VREF_SEL_B1_MASK, + value << SHU1_B1_DQ5_RG_RX_ARDQ_VREF_SEL_B1_SHIFT); +} + +static void dramc_set_tx_vref(u8 chn, u8 rank, u16 value) +{ + dramc_mode_reg_write_by_rank(chn, rank, 14, value | 0 << 6); +} + +static void set_rx_dly_factor(u8 chn, u8 rank, u8 type, u32 val) +{ + u8 i; + u32 value; + u32 mask; + + switch (type) { + case RX_DQ: + value = (val << 24 | val << 16 | val << 8 | val); + for (i = 2; i < 6; i++) { + write32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[i], + value); + write32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[i], + value); + } + break; + + case RX_DQM: + value = (val << 8 | val); + mask = SHU1_B0_DQ6_RK_RX_ARDQM0_F_DLY_B0_MASK | + SHU1_B0_DQ6_RK_RX_ARDQM0_R_DLY_B0_MASK; + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[6], + mask, value); + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[6], + mask, value); + break; + + case RX_DQS: + value = (val << 24 | val << 16); + mask = SHU1_B0_DQ6_RK_RX_ARDQS0_F_DLY_B0_MASK | + SHU1_B0_DQ6_RK_RX_ARDQS0_R_DLY_B0_MASK; + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[6], + mask, value); + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[6], + mask, value); + + } +} + +static void dramc_transfer_dly_tune(u8 chn, u32 dly, + struct tx_dly_coarse_fine_tune *dly_tune) +{ + u16 tmp_val; + + dly_tune->fine_tune = dly & (TX_DQ_COARSE_TUNE_TO_FINE_TUNE_TAP - 1); + + tmp_val = (dly / TX_DQ_COARSE_TUNE_TO_FINE_TUNE_TAP) << 1; + dly_tune->coarse_tune_small = tmp_val - ((tmp_val >> 3) << 3); + dly_tune->coarse_tune_large = tmp_val >> 3; + + tmp_val -= 4; + dly_tune->coarse_tune_small_oen = tmp_val - ((tmp_val >> 3) << 3); + dly_tune->coarse_tune_large_oen = tmp_val >> 3; +} + +static void set_tx_dly_factor(u32 chn, u8 rank, u8 type, u32 curr_val) +{ + u8 i; + struct tx_dly_coarse_fine_tune dly_tune = { }; + u32 coarse_tune_large = 0; + u32 coarse_tune_large_oen = 0; + u32 coarse_tune_small = 0; + u32 coarse_tune_small_oen = 0; + + dramc_transfer_dly_tune(chn, curr_val, &dly_tune); + + for (i = 0; i < 4; i++) { + coarse_tune_large += dly_tune.coarse_tune_large << (i * 4); + coarse_tune_large_oen += + dly_tune.coarse_tune_large_oen << (i * 4); + coarse_tune_small += dly_tune.coarse_tune_small << (i * 4); + coarse_tune_small_oen += + dly_tune.coarse_tune_small_oen << (i * 4); + } + if (type == TX_DQM) + dramc_dbg("%3d |%d %d %2d | [0]", curr_val, + dly_tune.coarse_tune_large, + dly_tune.coarse_tune_small, dly_tune.fine_tune); + + switch (type) { + case TX_DQM: + /* large coarse_tune setting */ + write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[0], + (coarse_tune_large_oen << 16) | coarse_tune_large); + write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[2], + (coarse_tune_small_oen << 16) | coarse_tune_small); + + write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[1], + (coarse_tune_large_oen << 16) | coarse_tune_large); + write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[3], + (coarse_tune_small_oen << 16) | coarse_tune_small); + + /* fine_tune delay setting */ + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[7], + SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_MASK, + dly_tune.fine_tune << 8); + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[7], + SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_MASK, + dly_tune.fine_tune << 8); + + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[7], + SHU1_B0_DQ7_RK_ARFINE_TUNE_DQM_B0_MASK, + dly_tune.fine_tune << 16); + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[7], + SHU1_B1_DQ7_RK_ARFINE_TUNE_DQM_B1_MASK, + dly_tune.fine_tune << 16); + break; + + case TX_DQ: + write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[0], + (coarse_tune_large_oen << 16) | coarse_tune_large); + write32(&ch[chn].ao.shu[0].rk[rank].selph_dq[2], + (coarse_tune_small_oen << 16) | coarse_tune_small); + + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[7], + SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_MASK, + dly_tune.fine_tune << 8); + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[7], + SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_MASK, + dly_tune.fine_tune << 8); + break; + + default: + break; + } +} + +static void set_dly_factor(u8 chn, u8 rank, u8 type, u32 dly) +{ + switch (type) { + case TX_WIN_MOVE_DQ_ONLY: + set_tx_dly_factor(chn, rank, TX_DQ, dly); + break; + + case TX_WIN_MOVE_DQ_DQM: + set_tx_dly_factor(chn, rank, TX_DQM, dly); + break; + + default: + dramc_dbg("%s Invalid type\n", __func__); + break; + } +} + +static void dramc_engine2_setpat(u8 chn, u8 testaudpat, + u8 log2loopcount, u8 Use_Len1_Flag) +{ + if (testaudpat == TEST_XTALK_PATTERN) { + if (Use_Len1_Flag != 0) + setbits_le32(&ch[chn].ao.test2_4, + 0x1 << TEST2_4_TEST_REQ_LEN1_SHIFT); + else + clrbits_le32(&ch[chn].ao.test2_4, + 0x1 << TEST2_4_TEST_REQ_LEN1_SHIFT); + setbits_le32(&ch[chn].ao.perfctl0, 1 << PERFCTL0_RWOFOEN_SHIFT); + + clrsetbits_le32(&ch[chn].ao.test2_3, + 0x1 << TEST2_3_TESTAUDPAT_SHIFT | TEST2_3_TESTCNT_MASK, + log2loopcount << 0); + + clrsetbits_le32(&ch[chn].ao.test2_4, + 0x1 << TEST2_4_TESTXTALKPAT_SHIFT | + 0x1 << TEST2_4_TESTAUDMODE_SHIFT | + 0x1 << TEST2_4_TESTAUDBITINV_SHIFT, + 0x1 << TEST2_4_TESTXTALKPAT_SHIFT); + + clrbits_le32(&ch[chn].ao.test2_4, + 1 << TEST2_4_TESTSSOPAT_SHIFT | + 0x1 << TEST2_4_TESTSSOXTALKPAT_SHIFT); + } else if (testaudpat == TEST_AUDIO_PATTERN) { + clrsetbits_le32(&ch[chn].ao.test2_4, + TEST2_4_TESTAUDINIT_MASK | + TEST2_4_TESTAUDINC_MASK | + (0x1 << TEST2_4_TESTXTALKPAT_SHIFT) | + (0x1 << TEST2_4_TESTAUDMODE_SHIFT) | + (0x1 << TEST2_4_TESTAUDBITINV_SHIFT), + (0x11 << 8) | (0xd << 0) | (0x1 << 14)); + + clrsetbits_le32(&ch[chn].ao.test2_3, + 0x1 << TEST2_3_TESTAUDPAT_SHIFT | TEST2_3_TESTCNT_MASK, + 0x1 << TEST2_3_TESTAUDPAT_SHIFT | log2loopcount << 0); + } else { + clrsetbits_le32(&ch[chn].ao.test2_3, + 0x1 << TEST2_3_TESTAUDPAT_SHIFT | TEST2_3_TESTCNT_MASK, + log2loopcount << 0); + clrbits_le32(&ch[chn].ao.test2_4, + 0x1 << TEST2_4_TESTXTALKPAT_SHIFT); + } +} + +static u32 dram_k_perbit(u8 chn, u8 engine_type) +{ + u32 err_value = 0x0; + + if (engine_type) { + dramc_engine2_setpat(chn, TEST_AUDIO_PATTERN, 0, 0); + err_value = dramc_engine2_run(chn, + TE_OP_WRITE_READ_CHECK, TEST_AUDIO_PATTERN); + dramc_engine2_setpat(chn, TEST_XTALK_PATTERN, 0, 0); + err_value |= dramc_engine2_run(chn, + TE_OP_WRITE_READ_CHECK, TEST_XTALK_PATTERN); + } else + err_value = dramc_rd_dqc_run(chn); + return err_value; +} + +static void dramc_check_dq_win(struct dqs_perbit_dly *p, + s16 dly_step, s16 last_step, u32 fail_bit) +{ + s16 dqdly_pass_win, best_pass_win; + + if (fail_bit == 0) { + if (p->first_dqdly_pass == -1) { + /* first DQ pass delay tap */ + p->first_dqdly_pass = dly_step; + } + + if ((p->last_dqdly_pass == -2) && (dly_step == last_step)) { + /* pass to the last tap */ + p->last_dqdly_pass = dly_step; + dqdly_pass_win = + p->last_dqdly_pass - p->first_dqdly_pass; + best_pass_win = + p->best_last_dqdly_pass + - p->best_first_dqdly_pass; + if (dqdly_pass_win > best_pass_win) { + p->best_last_dqdly_pass = p->last_dqdly_pass; + p->best_first_dqdly_pass = p->first_dqdly_pass; + } + /* clear to find the next pass range if it has */ + p->first_dqdly_pass = -1; + p->last_dqdly_pass = -2; + } + } else { + if ((p->first_dqdly_pass != -1) + && (p->last_dqdly_pass == -2)) { + p->last_dqdly_pass = dly_step - 1; + dqdly_pass_win = + p->last_dqdly_pass - p->first_dqdly_pass; + best_pass_win = + p->best_last_dqdly_pass + - p->best_first_dqdly_pass; + if (dqdly_pass_win > best_pass_win) { + p->best_last_dqdly_pass = p->last_dqdly_pass; + p->best_first_dqdly_pass = p->first_dqdly_pass; + } + /* clear to find the next pass range if it has */ + p->first_dqdly_pass = -1; + p->last_dqdly_pass = -2; + } + } +} + +static int dramk_calcu_best_vref(u8 cal_type, + struct dqs_perbit_dly vref_dly[], struct dqs_perbit_dly delay[], + u32 min_win_size, u32 max_win_sum) +{ + u8 bit; + u32 win_size; + u32 win_size_sum = 0; + static u32 min_win_size_vref; + + if (cal_type == (RX_WIN | (1 << 1))) { + for (bit = 0; bit < DQ_DATA_WIDTH; bit++) { + win_size_sum += + (delay[bit].best_last_dqdly_pass - + delay[bit].best_first_dqdly_pass + 1); + win_size_sum += + (delay[bit].best_last_dqsdly_pass - + delay[bit].best_first_dqsdly_pass + 1); + } + if (win_size_sum > max_win_sum) { + max_win_sum = win_size_sum; + for (bit = 0; bit < DQ_DATA_WIDTH; bit++) { + vref_dly[bit].vref = delay[bit].vref; + vref_dly[bit].best_dqdly = + delay[bit].best_dqdly; + vref_dly[bit].best_first_dqdly_pass = + delay[bit].best_first_dqdly_pass; + vref_dly[bit].best_last_dqdly_pass = + delay[bit].best_last_dqdly_pass; + vref_dly[bit].best_first_dqsdly_pass = + delay[bit].best_first_dqsdly_pass; + vref_dly[bit].best_last_dqsdly_pass = + delay[bit].best_last_dqsdly_pass; + } + } + if (win_size_sum < (max_win_sum * 95 / 100)) + return 1; + } else if (cal_type == TX_DQ_DQS_MOVE_DQ_ONLY) { + for (bit = 0; bit < DQ_DATA_WIDTH; bit++) { + win_size = + (delay[bit].best_last_dqdly_pass - + delay[bit].best_first_dqdly_pass + 1); + if (win_size < min_win_size) + min_win_size = win_size; + win_size_sum += win_size; + } + + if ((win_size_sum > max_win_sum) + && (min_win_size >= min_win_size_vref)) { + max_win_sum = win_size_sum; + min_win_size_vref = min_win_size; + for (bit = 0; bit < DQ_DATA_WIDTH; bit++) { + vref_dly[bit].vref = delay[bit].vref; + vref_dly[bit].best_dqdly = + delay[bit].best_dqdly; + vref_dly[bit].best_first_dqdly_pass = + delay[bit].best_first_dqdly_pass; + vref_dly[bit].best_last_dqdly_pass = + delay[bit].best_last_dqdly_pass; + } + } + + } else { + for (bit = 0; bit < DQ_DATA_WIDTH; bit++) { + vref_dly[bit].vref = delay[bit].vref; + vref_dly[bit].best_dqdly = delay[bit].best_dqdly; + vref_dly[bit].best_first_dqdly_pass = + delay[bit].best_first_dqdly_pass; + vref_dly[bit].best_last_dqdly_pass = + delay[bit].best_last_dqdly_pass; + vref_dly[bit].best_first_dqsdly_pass = + delay[bit].best_first_dqsdly_pass; + vref_dly[bit].best_last_dqsdly_pass = + delay[bit].best_last_dqsdly_pass; + } + } + return 0; +} + +static u8 dramc_calcu_best_dly(u8 bit, + struct dqs_perbit_dly *p, u32 *p_max_byte) +{ + u8 fail = 0; + u8 hold, setup; + + hold = p->best_last_dqsdly_pass - p->best_first_dqsdly_pass + 1; + setup = p->best_last_dqdly_pass - p->best_first_dqdly_pass + 1; + + if (hold > setup) { + p->best_dqdly = 0; + p->best_dqsdly = (setup != 0) ? (hold - setup) / 2 : + (hold - setup) / 2 + p->best_first_dqsdly_pass; + + if (p->best_dqsdly > *p_max_byte) + *p_max_byte = p->best_dqsdly; + + } else if (hold < setup) { + p->best_dqsdly = 0; + p->best_dqdly = (hold != 0) ? (setup - hold) / 2 : + (setup - hold) / 2 + p->best_first_dqdly_pass; + + } else { /* hold time == setup time */ + p->best_dqsdly = 0; + p->best_dqdly = 0; + + if (hold == 0) { + dramc_dbg("ERROR, error bit %d, " + "setup_time = hold_time = 0\n", bit); + fail = 1; + } + } + + dramc_dbg("bit#%d : dq =%d dqs=%d win=%d (%d, %d)\n", + bit, setup, hold, setup + hold, + p->best_dqdly, p->best_dqsdly); + + return fail; +} + +static void dramc_calcu_tx_perbyte_dly(u8 bit, + struct dqs_perbit_dly *p, struct per_byte_dly *byte_delay_prop) +{ + s16 win_center; + win_center = (p->best_first_dqdly_pass + p->best_last_dqdly_pass) >> 1; + + if (win_center < byte_delay_prop->min_center) + byte_delay_prop->min_center = win_center; + if (win_center > byte_delay_prop->max_center) + byte_delay_prop->max_center = win_center; +} + +static void set_tx_best_dly_factor(u8 chn, u8 rank, + struct per_byte_dly *tx_perbyte_dly, + u16 dq_precal_result[]) +{ + u8 i, rank_idx; + u32 coarse_tune_large = 0; + u32 coarse_tune_large_oen = 0; + u32 coarse_tune_small = 0; + u32 coarse_tune_small_oen = 0; + u16 dq_oen[DQS_NUMBER] = { }, dqm_oen[DQS_NUMBER] = { }; + struct tx_dly_coarse_fine_tune perbyte_dqdly_tune[DQS_NUMBER] = { }; + struct tx_dly_coarse_fine_tune perbyte_dqmdly_tune[DQS_NUMBER] = { }; + + for (i = 0; i < DQS_NUMBER; i++) { + dramc_transfer_dly_tune(chn, tx_perbyte_dly[i].final_dly, + &perbyte_dqdly_tune[i]); + dramc_transfer_dly_tune(chn, dq_precal_result[i], + &perbyte_dqmdly_tune[i]); + + coarse_tune_large += + perbyte_dqdly_tune[i].coarse_tune_large << (i * 4); + coarse_tune_large_oen += + perbyte_dqdly_tune[i].coarse_tune_large_oen << (i * 4); + coarse_tune_small += + perbyte_dqdly_tune[i].coarse_tune_small << (i * 4); + coarse_tune_small_oen += + perbyte_dqdly_tune[i].coarse_tune_small_oen << (i * 4); + dq_oen[i] = + (perbyte_dqdly_tune[i].coarse_tune_large_oen << 3) + + (perbyte_dqdly_tune[i].coarse_tune_small_oen << 5) + + perbyte_dqdly_tune[i].fine_tune; + dqm_oen[i] = + (perbyte_dqmdly_tune[i].coarse_tune_large_oen << 3) + + (perbyte_dqmdly_tune[i].coarse_tune_small_oen << 5) + + perbyte_dqmdly_tune[i].fine_tune; + } + + for (rank_idx = rank; rank_idx < RANK_MAX; rank_idx++) { + write32(&ch[chn].ao.shu[0].rk[rank_idx].selph_dq[0], + (coarse_tune_large_oen << 16) | + coarse_tune_large); + write32(&ch[chn].ao.shu[0].rk[rank_idx].selph_dq[2], + (coarse_tune_small_oen << 16) | + coarse_tune_small); + + write32(&ch[chn].ao.shu[0].rk[rank_idx].selph_dq[1], + (coarse_tune_large_oen << 16) | + coarse_tune_large); + write32(&ch[chn].ao.shu[0].rk[rank_idx].selph_dq[3], + (coarse_tune_small_oen << 16) | + coarse_tune_small); + } + + for (rank_idx = rank; rank_idx < RANK_MAX; rank_idx++) { + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank_idx].b[0].dq[7], + SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_MASK | + SHU1_B0_DQ7_RK_ARFINE_TUNE_DQM_B0_MASK, + perbyte_dqdly_tune[0].fine_tune << + SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_SHIFT | + perbyte_dqmdly_tune[0].fine_tune << + SHU1_B0_DQ7_RK_ARFINE_TUNE_DQM_B0_SHIFT); + + clrsetbits_le32(&ch[chn].phy.shu[0].rk[rank_idx].b[1].dq[7], + SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_MASK | + SHU1_B1_DQ7_RK_ARFINE_TUNE_DQM_B1_MASK, + perbyte_dqdly_tune[1].fine_tune << + SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_SHIFT | + perbyte_dqmdly_tune[1].fine_tune << + SHU1_B1_DQ7_RK_ARFINE_TUNE_DQM_B1_SHIFT); + } +} + +static void set_rx_best_dly_factor(u8 chn, u8 rank, + struct dqs_perbit_dly *dqdqs_perbit_dly, + u32 *max_dqsdly_byte, u32 *ave_dqm_dly) +{ + u32 i, value = 0; + u8 index, byte; + + for (i = 0; i < DQS_NUMBER; i++) { + value = (max_dqsdly_byte[i] << 24) | + (max_dqsdly_byte[i] << 16) | + (ave_dqm_dly[i] << 8) | (ave_dqm_dly[i] << 0); + + /* Delay dqs/dqm */ + write32(&ch[chn].phy.shu[0].rk[rank].b[i].dq[6], value); + } + dram_phy_reset(chn); + + value = 0; + for (i = 0; i < DQ_DATA_WIDTH; i += 2) { + byte = i / DQS_BIT_NUMBER; + index = 2 + ((i % 8) * 2) / 4; + value = + dqdqs_perbit_dly[i + 1].best_dqdly << 24 | + dqdqs_perbit_dly[i + 1].best_dqdly << 16 | + dqdqs_perbit_dly[i].best_dqdly << 8 | + dqdqs_perbit_dly[i].best_dqdly; + write32(&ch[chn].phy.shu[0].rk[rank].b[byte].dq[index], + value); + } + +} + +static void dramc_get_vref_range(u8 cal_type, u8 enable, + u8 *begin, u8 *end, u8 *step) +{ + if (enable) { + if (cal_type == RX_WIN) { + *begin = RX_VREF_BEGIN; + *end = RX_VREF_END; + *step = RX_VREF_STEP; + } else if (cal_type == TX_WIN_MOVE_DQ_ONLY) { + *begin = TX_VREF_BEGIN; + *end = TX_VREF_END; + *step = TX_VREF_STEP; + } + } else { + *begin = 0; + *end = 1; + *step = 1; + } +} + +static u32 dramc_get_smallest_dqs_dly(u8 chn, u8 rank) +{ + u32 dq_coarse_dly = 0; + u32 dq_fine_dly = 0; + u32 tmp_dly = 0; + u32 smallest_dqs_dly = 0xffff; + int i = 0; + const struct sdram_params *params = get_sdram_config(); + + for (i = 0; i < DQS_NUMBER; i++) { + dq_coarse_dly = + (read32(&ch[chn].ao.shu[0].selph_dqs0) >> (i << 2)) & 0x7; + dq_fine_dly = + (read32(&ch[chn].ao.shu[0].selph_dqs1) >> (i << 2)) & 0x7; + + tmp_dly = + (((dq_coarse_dly << 3) + dq_fine_dly) << 5) + params->wr_level[chn][rank][i]; + if (tmp_dly < smallest_dqs_dly) + smallest_dqs_dly = tmp_dly; + } + + return smallest_dqs_dly; +} +static void dramc_get_dly_range(u8 chn, u8 rank, u8 cal_type, u16 *pre_cal, + s16 *begin, s16 *end) +{ + u16 pre_dq_dly; + + if (cal_type == TX_WIN_MOVE_DQ_DQM) { + *begin = dramc_get_smallest_dqs_dly(chn, rank); + *end = *begin + 256; + } else if (cal_type == TX_WIN_MOVE_DQ_ONLY) { + pre_dq_dly = + (pre_cal[0] > pre_cal[1]) ? pre_cal[1] : pre_cal[0]; + if (pre_dq_dly > 24) + pre_dq_dly -= 24; + else + pre_dq_dly = 0; + + *begin = pre_dq_dly; + *end = *begin + 64; + } +} + +static void dramc_check_dqs_win(struct dqs_perbit_dly *p, + u8 dly_step, u8 last_step, u32 fail_bit) +{ + s8 dqsdly_pass_win, best_pass_win; + + if (fail_bit == 0) { + if (p->first_dqsdly_pass == -1) { + /* first DQS pass delay tap */ + p->first_dqsdly_pass = dly_step; + } + if ((p->last_dqsdly_pass == -2) && (dly_step == last_step)) { + /* pass to the last tap */ + p->last_dqsdly_pass = dly_step; + dqsdly_pass_win = p->last_dqsdly_pass + - p->first_dqsdly_pass; + best_pass_win = p->best_last_dqsdly_pass + - p->best_first_dqsdly_pass; + if (dqsdly_pass_win > best_pass_win) { + p->best_last_dqsdly_pass = + p->last_dqsdly_pass; + p->best_first_dqsdly_pass = + p->first_dqsdly_pass; + } + /* clear to find the next pass range if it has */ + p->first_dqsdly_pass = -1; + p->last_dqsdly_pass = -2; + } + } else { + if ((p->first_dqsdly_pass != -1) + && (p->last_dqsdly_pass == -2)) { + p->last_dqsdly_pass = dly_step - 1; + dqsdly_pass_win = p->last_dqsdly_pass + - p->first_dqsdly_pass; + best_pass_win = p->best_last_dqsdly_pass + - p->best_first_dqsdly_pass; + if (dqsdly_pass_win > best_pass_win) { + p->best_last_dqsdly_pass + = p->last_dqsdly_pass; + p->best_first_dqsdly_pass + = p->first_dqsdly_pass; + } + /* clear to find the next pass range if it has */ + p->first_dqsdly_pass = -1; + p->last_dqsdly_pass = -2; + } + } +} + +static void dramc_set_dqdqs_dly(u8 chn, u8 rank, s32 dly) +{ + if (dly <= 0) { + /* Hold time calibration */ + set_rx_dly_factor(chn, rank, RX_DQS, -dly); + dram_phy_reset(chn); + } else { + /* Setup time calibration */ + set_rx_dly_factor(chn, rank, RX_DQS, 0); + set_rx_dly_factor(chn, rank, RX_DQM, dly); + dram_phy_reset(chn); + set_rx_dly_factor(chn, rank, RX_DQ, dly); + } +} + +static u8 dramc_rx_window_perbit_cal(u8 chn, u8 cal_type, + u8 rank, u8 engine_type) +{ + u8 vref; + u8 vref_begin = 0, vref_end = 1, vref_step = 1; + u8 vref_scan_enable; + s8 fail = 0; + u8 i, bit, max_dq_taps; + u8 index, max_limit; + s16 dly; + u8 dly_step = 1; + u8 type = cal_type; + u32 err_value, fail_bit; + u32 min_win_size = 0xffff; + u32 max_win_size_sum = 0; + static u32 max_dqsdly_byte[DQS_NUMBER], ave_dqmdly_byte[DQS_NUMBER]; + static struct dqs_perbit_dly vref_dq_perbit_dly[DQ_DATA_WIDTH]; + struct dqs_perbit_dly dqdqs_perbit_dly[DQ_DATA_WIDTH]; + + if (engine_type && (rank == RANK_0)) { + vref_scan_enable = 1; + dramc_vref_enable(chn); + } else { + vref_scan_enable = 0; + } + + dramc_dbg("%s [Rank %d] [Channel %d] Calibration Type:%d, engine:%d,vref_enable:%d\n", + __func__, rank, chn, type, engine_type, vref_scan_enable); + + if (engine_type) + dramc_engine2_init(chn, rank, DEFAULT_TEST2_1_CAL, + DEFAULT_TEST2_2_CAL, TEST_XTALK_PATTERN, 0); + else + dramc_rd_dqc_init(chn, rank); + + dramc_get_vref_range(type, vref_scan_enable, + &vref_begin, &vref_end, &vref_step); + + /* if calibration data is allready stored in emmc, + * Vref end need change */ + for (vref = vref_begin; vref < vref_end; vref += vref_step) { + if (vref_scan_enable) + dramc_set_rx_vref(chn, vref); + + for (i = 0; i < DQ_DATA_WIDTH; i++) { + dqdqs_perbit_dly[i].vref = vref; + dqdqs_perbit_dly[i].first_dqdly_pass = -1; + dqdqs_perbit_dly[i].last_dqdly_pass = -2; + dqdqs_perbit_dly[i].first_dqsdly_pass = -1; + dqdqs_perbit_dly[i].last_dqsdly_pass = -2; + dqdqs_perbit_dly[i].best_first_dqdly_pass = -1; + dqdqs_perbit_dly[i].best_last_dqdly_pass = -2; + dqdqs_perbit_dly[i].best_first_dqsdly_pass = -1; + dqdqs_perbit_dly[i].best_last_dqsdly_pass = -2; + } + + set_rx_dly_factor(chn, rank, RX_DQM, FIRST_DQ_DELAY); + set_rx_dly_factor(chn, rank, RX_DQ, FIRST_DQ_DELAY); + + max_dq_taps = MAX_RX_DQDLY_TAPS; + for (dly = FIRST_DQS_DELAY; dly < max_dq_taps; + dly += dly_step) { + dramc_set_dqdqs_dly(chn, rank, dly); + err_value = dram_k_perbit(chn, engine_type); + if (!vref_scan_enable) + dramc_dbg("delay %d ", dly); + + for (bit = 0; bit < DQ_DATA_WIDTH; bit++) { + fail_bit = err_value & ((u32) 1 << bit); + if (dly < 0) { + dramc_check_dqs_win( + &(dqdqs_perbit_dly[bit]), + -dly, -FIRST_DQS_DELAY, + fail_bit); + } else + dramc_check_dq_win( + &(dqdqs_perbit_dly[bit]), + dly, max_dq_taps, fail_bit); + if (!vref_scan_enable) { + if (fail_bit == 0) + dramc_dbg("o"); + else + dramc_dbg("x"); + } + } + + if (!vref_scan_enable) + dramc_dbg(" [MSB]\n"); + } + if (dramk_calcu_best_vref + (type | (1 << engine_type), vref_dq_perbit_dly, + dqdqs_perbit_dly, min_win_size, max_win_size_sum)) + break; + } + + if (engine_type) + dramc_engine2_end(chn); + else + dramc_rd_dqc_end(chn); + + if (vref_scan_enable) + dramc_set_rx_vref(chn, vref_dq_perbit_dly[0].vref); + for (i = 0; i < DQS_NUMBER; i++) { + max_dqsdly_byte[i] = 0; + ave_dqmdly_byte[i] = 0; + } + + for (i = 0; i < DQ_DATA_WIDTH; i++) { + index = i / DQS_BIT_NUMBER; + fail |= dramc_calcu_best_dly(i, + &vref_dq_perbit_dly[i], &max_dqsdly_byte[index]); + } + + for (i = 0; i < DQ_DATA_WIDTH; i++) { + index = i / DQS_BIT_NUMBER; + /* set DQS to max for 8-bit */ + if (dqdqs_perbit_dly[i].best_dqsdly < max_dqsdly_byte[index]) { + /* Delay DQ to compensate extra DQS delay */ + dly = max_dqsdly_byte[index] - + vref_dq_perbit_dly[i].best_dqsdly; + vref_dq_perbit_dly[i].best_dqdly += dly; + max_limit = MAX_DQDLY_TAPS - 1; + if (vref_dq_perbit_dly[i].best_dqdly > max_limit) + vref_dq_perbit_dly[i].best_dqdly = max_limit; + } + + ave_dqmdly_byte[index] += vref_dq_perbit_dly[i].best_dqdly; + if ((i + 1) % DQS_BIT_NUMBER == 0) + ave_dqmdly_byte[index] /= DQS_BIT_NUMBER; + } + + if (fail == 1) { + dramc_dbg("FAIL on perbit_window_cal()\n"); + return -1; + } + + set_rx_best_dly_factor(chn, rank, vref_dq_perbit_dly, max_dqsdly_byte, + ave_dqmdly_byte); + return 0; +} + +static void dramc_tx_window_perbit_cal(u8 chn, u8 rank, u8 cal_type) +{ + u8 vref, vref_begin, vref_end, vref_step; + u8 vref_scan_enable; + s16 dly_begin = 0, dly_end = 0; + u8 i, bit, index; + s16 dly; + u8 dly_step = 1; + u32 win_sum; + u32 err_value, fail_bit; + struct per_byte_dly tx_perbyte_dly[DQS_NUMBER]; + static u16 dq_precal_result[DQS_NUMBER]; + struct dqs_perbit_dly dqdqs_perbit_dly[DQ_DATA_WIDTH]; + struct dqs_perbit_dly vref_dqdqs_perbit_dly[DQ_DATA_WIDTH]; + u32 min_win_size = 0xffff; + u32 max_win_size_sum = 0; + + if (cal_type == TX_WIN_MOVE_DQ_ONLY) + vref_scan_enable = 1; + else + vref_scan_enable = 0; + + dramc_dbg("%s [Rank %d][Channel %d] Calibration Type:%d\n", + __func__, rank, chn, cal_type); + + write32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[0], 0); + write32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[0], 0); + clrbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[1], 0xf); + clrbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[1], 0xf); + + setbits_le32(&ch[chn].phy.misc_ctrl1, + 0x1 << MISC_CTRL1_R_DMAR_FINE_TUNE_DQ_SW_SHIFT); + setbits_le32(&ch[chn].ao.dqsoscr, + 0x1 << DQSOSCR_AR_COARSE_TUNE_DQ_SW_SHIFT); + + dramc_engine2_init(chn, rank, DEFAULT_TEST2_1_CAL, DEFAULT_TEST2_2_CAL, + TEST_XTALK_PATTERN, 0); + + dramc_get_vref_range(cal_type, vref_scan_enable, + &vref_begin, &vref_end, &vref_step); + for (vref = vref_begin; vref < vref_end; vref += vref_step) { + + win_sum = 0; + for (i = 0; i < DQ_DATA_WIDTH; i++) { + dqdqs_perbit_dly[i].vref = vref; + dqdqs_perbit_dly[i].first_dqdly_pass = -1; + dqdqs_perbit_dly[i].last_dqdly_pass = -2; + dqdqs_perbit_dly[i].best_first_dqdly_pass = -1; + dqdqs_perbit_dly[i].best_last_dqdly_pass = -2; + } + + if (vref_scan_enable) + dramc_set_tx_vref(chn, rank, vref); + + dramc_get_dly_range(chn, rank, cal_type, dq_precal_result, + &dly_begin, &dly_end); + + dramc_dbg("delay range: (%d - %d)\n", dly_begin, dly_end); + for (dly = dly_begin; dly < dly_end; dly += dly_step) { + set_dly_factor(chn, rank, cal_type, dly); + dramc_dbg("delay = %d ", dly); + err_value = dram_k_perbit(chn, 1); + + for (bit = 0; bit < DQ_DATA_WIDTH; bit++) { + fail_bit = err_value & ((u32) 1 << bit); + dramc_check_dq_win(&(dqdqs_perbit_dly[bit]), + dly, dly_end, fail_bit); + if (fail_bit == 0) + dramc_dbg("o"); + else + dramc_dbg("x"); + } + + dramc_dbg(" [MSB]\n"); + } + + for (bit = 0; bit < DQ_DATA_WIDTH; bit++) { + dramc_dbg("dq[%d] win(%d ~ %d)\n", + bit, dqdqs_perbit_dly[bit].best_first_dqdly_pass, + dqdqs_perbit_dly[bit].best_last_dqdly_pass); + } + + dramk_calcu_best_vref(cal_type, vref_dqdqs_perbit_dly, + dqdqs_perbit_dly, min_win_size, max_win_size_sum); + } + dramc_engine2_end(chn); + + dramc_dbg("Final Vref is %d\n", vref_dqdqs_perbit_dly[0].vref); + if (vref_scan_enable) + dramc_set_tx_vref(chn, rank, vref_dqdqs_perbit_dly[0].vref); + + for (i = 0; i < DQS_NUMBER; i++) { + tx_perbyte_dly[i].min_center = 0xffff; + tx_perbyte_dly[i].max_center = 0; + } + + for (i = 0; i < DQ_DATA_WIDTH; i++) { + index = i / DQS_BIT_NUMBER; + dramc_calcu_tx_perbyte_dly(i, &vref_dqdqs_perbit_dly[i], + &tx_perbyte_dly[index]); + } + + for (i = 0; i < DQS_NUMBER; i++) { + tx_perbyte_dly[i].final_dly = + (tx_perbyte_dly[i].max_center + + tx_perbyte_dly[i].min_center) >> 1; + dq_precal_result[i] = tx_perbyte_dly[i].final_dly; + dramc_dbg("dq_perbyte_dly[%d] = %d\n", + i, dq_precal_result[i]); + } + + set_tx_best_dly_factor(chn, rank, tx_perbyte_dly, dq_precal_result); +} + +static void dramc_read_dbi_onoff(u8 onoff) +{ + u8 chn; + + /* DRAMC Read-DBI On/Off */ + for (chn = 0; chn < CHANNEL_NUM; chn++) { + clrsetbits_le32(&ch[chn].phy.shu[0].b[0].dq[7], + 0x1 << SHU1_B0_DQ7_R_DMDQMDBI_SHU_B0_SHIFT, + (onoff << SHU1_B0_DQ7_R_DMDQMDBI_SHU_B0_SHIFT)); + clrsetbits_le32(&ch[chn].phy.shu[0].b[1].dq[7], + 0x1 << SHU1_B0_DQ7_R_DMDQMDBI_SHU_B0_SHIFT, + (onoff << SHU1_B0_DQ7_R_DMDQMDBI_SHU_B0_SHIFT)); + } +} + +static void dramc_write_dbi_onoff(u8 onoff) +{ + u8 u1value, chn; + + /* DRAMC Write-DBI On/Off */ + for (chn = 0; chn < CHANNEL_NUM; chn++) { + clrsetbits_le32(&ch[chn].ao.shu[0].wodt, + 0x1 << SHU1_WODT_DBIWR_SHIFT, + (onoff << SHU1_WODT_DBIWR_SHIFT)); + } + + u1value = read32(&ch[0].ao.shu[0].wodt); + dramc_dbg("DRAMC Write-DBI On/Off = %d\n", u1value); +} + +u8 dramc_zq_calibration(u8 chn, u8 rank) +{ + u32 u4Response; + u32 u4TimeCnt; + u32 *u4RegBackup[] = { + &ch[chn].ao.mrs, + &ch[chn].ao.dramc_pd_ctrl, + &ch[chn].ao.ckectrl, + }; + + dramc_dbg("[%s] rank:%d\n", __func__, rank); + u4TimeCnt = TIME_OUT_CNT; + + save_restore_multi_reg(SAVE_VALUE, + u4RegBackup, ARRAY_SIZE(u4RegBackup)); + + setbits_le32(&ch[chn].ao.dramc_pd_ctrl, 0x1 << 26); + + cke_fix_onoff(CKE_FIXON, chn); + + clrsetbits_le32(&ch[chn].ao.mrs, + MRS_MPCRK_MASK, (rank << MRS_MPCRK_SHIFT)); + setbits_le32(&ch[chn].ao.mpc_option, + (0x1 << MPC_OPTION_MPCRKEN_SHIFT)); + + setbits_le32(&ch[chn].ao.spcmd, (0x1 << SPCMD_ZQCEN_SHIFT)); + do { + u4Response = + (read32(&ch[chn].nao.spcmdresp) & + (0x1 << SPCMDRESP_ZQC_RESPONSE_SHIFT)) >> + SPCMDRESP_ZQC_RESPONSE_SHIFT; + u4TimeCnt--; + udelay(1); + dramc_dbg("try:%d\n", u4TimeCnt); + } while ((u4Response == 0) && (u4TimeCnt > 0)); + + if (u4TimeCnt == 0) { + dramc_dbg("ZQCAL Start fail (time out)\n"); + return 1; + } + + clrbits_le32(&ch[chn].ao.spcmd, (0x1 << SPCMD_ZQCEN_SHIFT)); + + udelay(1); + u4TimeCnt = TIME_OUT_CNT; + + setbits_le32(&ch[chn].ao.spcmd, (0x1 << SPCMD_ZQLATEN_SHIFT)); + do { + u4Response = (read32(&ch[chn].nao.spcmdresp) & + (0x1 << SPCMDRESP_ZQLAT_RESPONSE_SHIFT)) >> + SPCMDRESP_ZQLAT_RESPONSE_SHIFT; + u4TimeCnt--; + udelay(1); + dramc_dbg("%d\n", u4TimeCnt); + } while ((u4Response == 0) && (u4TimeCnt > 0)); + + if (u4TimeCnt == 0) { + dramc_dbg("ZQCAL Latch fail (time out)\n"); + return 1; + } + + clrbits_le32(&ch[chn].ao.spcmd, (0x1 << SPCMD_ZQLATEN_SHIFT)); + + udelay(1); + + save_restore_multi_reg(RESTORE_VALUE, + u4RegBackup, ARRAY_SIZE(u4RegBackup)); + + return 0; +} + +static void dle_factor_handler(u8 chn, u8 curr_val) +{ + if (curr_val < 2) + curr_val = 2; + clrsetbits_le32(&ch[chn].ao.shu[0].conf[1], + (SHU_CONF1_DATLAT_MASK) | (SHU_CONF1_DATLAT_DSEL_MASK) | + (SHU_CONF1_DATLAT_DSEL_PHY_MASK), + (curr_val << SHU_CONF1_DATLAT_SHIFT) | + ((curr_val - 2) << SHU_CONF1_DATLAT_DSEL_SHIFT) | + ((curr_val - 2) << SHU_CONF1_DATLAT_DSEL_PHY_SHIFT)); + dram_phy_reset(chn); +} + +static u32 rx_datlat_result(u8 chn, u8 rank, u8 type, u8 best_step) +{ + static u8 aru1RxDatlatResult[CHANNEL_NUM][RANK_MAX] = {0x0}; + + if (type == SAVE_VALUE) { + aru1RxDatlatResult[chn][rank] = best_step; + return 0; + } + + return aru1RxDatlatResult[chn][rank]; +} + +static u8 dramc_rxdatlat_scan(u8 chn, u8 rank, + enum dram_datlat_type use_rxtx_scan) +{ + u8 ii; + u32 u4prv_register_080; + u32 u4err_value = 0xffffffff; + u8 ucfirst, ucbegin, ucsum, ucbest_step; + u16 u2DatlatBegin; + + dramc_show("[DATLAT]\nCH%d RK%d, use_rxtx_scan=%d\n\n", + chn, rank, use_rxtx_scan); + + u4prv_register_080 = read32(&ch[chn].ao.shu[0].conf[1]); + ucbest_step = (u8) (read32(&ch[chn].ao.shu[0].conf[1]) + & (SHU_CONF1_DATLAT_MASK)); + dramc_dbg("DATLAT Default: 0x%x\n", ucbest_step); + + ucfirst = 0xff; + ucbegin = 0; + ucsum = 0; + + dramc_engine2_init(chn, rank, DEFAULT_TEST2_1_CAL, DEFAULT_TEST2_2_CAL, + TEST_XTALK_PATTERN, 0); + + u2DatlatBegin = 7; + for (ii = u2DatlatBegin; ii < DATLAT_TAP_NUMBER; ii++) { + dle_factor_handler(chn, ii); + + if (use_rxtx_scan == DATLAT_USE_DEFAULT) { + u4err_value = + dramc_engine2_run(chn, + TE_OP_WRITE_READ_CHECK, + TEST_XTALK_PATTERN); + } + if (u4err_value == 0) { + if (ucbegin == 0) { + ucfirst = ii; + ucbegin = 1; + } + if (ucbegin == 1) { + ucsum++; + if (ucsum > 4) + break; + } + } else { + if (ucbegin == 1) + ucbegin = 0xff; + } + + dramc_show("TAP=%2d, err_value=0x%8x, sum=%d\n", + ii, u4err_value, ucsum); + } + + dramc_engine2_end(chn); + + if (ucsum == 0) + dramc_show("no DATLAT taps pass, DATLAT calibration fail!\n"); + else if (ucsum <= 3) + ucbest_step = ucfirst + (ucsum >> 1); + else + ucbest_step = ucfirst + 2; + + rx_datlat_result(chn, rank, SAVE_VALUE, ucbest_step); + dramc_dbg("pattern=%d first_step=%d total pass=%d best_step=%d\n", + TEST_XTALK_PATTERN, ucfirst, ucsum, ucbest_step); + + if (ucsum < 4) + dramc_dbg("[NOTICE] CH%d, DatlatSum %d\n", chn, ucsum); + + if (ucsum == 0) { + dramc_show("DATLAT calibration fail," + "write back to default values!\n"); + write32(&ch[chn].ao.shu[0].conf[1], u4prv_register_080); + } else { + dle_factor_handler(chn, ucbest_step); + } + + clrsetbits_le32(&ch[chn].ao.padctrl, (PADCTRL_DQIENQKEND_MASK), + (0x1 << PADCTRL_DQIENQKEND_SHIFT) | + (0x1 << PADCTRL_DQIENLATEBEGIN_SHIFT)); + return ucsum; +} + +static void dramc_rx_datlat_cal(u8 chn, u8 rank) +{ + u8 u1DatlatWindowSum; + + u1DatlatWindowSum = dramc_rxdatlat_scan(chn, rank, DATLAT_USE_DEFAULT); +} + +static void dramc_dual_rank_rx_datlat_cal(u8 chn) +{ + u8 u1FinalDatlat, u1Datlat0, u1Datlat1; + + u1Datlat0 = rx_datlat_result(chn, RANK_0, RESTORE_VALUE, 0); + u1Datlat1 = rx_datlat_result(chn, RANK_1, RESTORE_VALUE, 0); + + if (u1Datlat0 > u1Datlat1) + u1FinalDatlat = u1Datlat0; + else + u1FinalDatlat = u1Datlat1; + + dle_factor_handler(chn, u1FinalDatlat); + dramc_dbg("[%s] RK0: %d, RK1: %d, Final_Datlat %d\n", + __func__, u1Datlat0, u1Datlat1, u1FinalDatlat); +} + +static void imp_cal_vref_sel(u8 term_option, u8 u1ImpCalStage) +{ + u8 u1RegTmpValue = 0; + + if (term_option == 1) { + u1RegTmpValue = IMP_LP4X_TERM_VREF_SEL; + } else { + if (u1ImpCalStage == IMPCAL_STAGE_DRVP) + u1RegTmpValue = IMP_DRVP_LP4X_UNTERM_VREF_SEL; + else if (u1ImpCalStage == IMPCAL_STAGE_DRVN) + u1RegTmpValue = IMP_DRVN_LP4X_UNTERM_VREF_SEL; + else + u1RegTmpValue = IMP_TRACK_LP4X_UNTERM_VREF_SEL; + } + + dramc_dbg("[%s] IMP_VREF_SEL 0x%x\n", __func__, u1RegTmpValue); + + clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[11], + 0x3f << 8, u1RegTmpValue << 8); +} + +void dramc_sw_impedance_save_register(const struct sdram_params *params) +{ + int tmp; + u32 broadcast_bak; + u8 term_opt, ca_term_option = 0, dq_term_option = 1; + u32 uSwImpedanceResult[2][4] = { {0}, {0} }; + + uSwImpedanceResult[0][0] = params->impedance[ca_term_option][0]; + uSwImpedanceResult[0][1] = params->impedance[ca_term_option][1]; + uSwImpedanceResult[0][2] = params->impedance[ca_term_option][2]; + uSwImpedanceResult[0][3] = params->impedance[ca_term_option][3]; + + uSwImpedanceResult[1][0] = params->impedance[dq_term_option][0]; + uSwImpedanceResult[1][1] = params->impedance[dq_term_option][1]; + uSwImpedanceResult[1][2] = params->impedance[dq_term_option][2]; + uSwImpedanceResult[1][3] = params->impedance[dq_term_option][3]; + + broadcast_bak = get_dramc_broadcast(); + + uSwImpedanceResult[ODT_OFF][2] = uSwImpedanceResult[ODT_ON][2]; + uSwImpedanceResult[ODT_OFF][3] = uSwImpedanceResult[ODT_ON][3]; + dramc_broadcast_onoff(DRAMC_BROADCAST_ON); + + tmp = 3; + clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[11], + 0xFF, tmp); + + /* Set IMP_VREF_SEL value for DRVP */ + imp_cal_vref_sel(dq_term_option, IMPCAL_STAGE_DRVP); + + /* DQ */ + clrsetbits_le32(&ch[0].ao.shu[0].drving[0], (0x1F << 5)|(0x1F << 0), + (uSwImpedanceResult[dq_term_option][0] << 5) | + (uSwImpedanceResult[dq_term_option][1] << 0)); + clrsetbits_le32(&ch[0].ao.shu[0].drving[1], + (0x1F << 25)|(0x1F << 20) | (1 << 31), + (uSwImpedanceResult[dq_term_option][0] << 25) | + (uSwImpedanceResult[dq_term_option][1] << 20) | + (!dq_term_option << 31)); + clrsetbits_le32(&ch[0].ao.shu[0].drving[2], (0x1F << 5)|(0x1F << 0), + (uSwImpedanceResult[dq_term_option][2] << 5) | + (uSwImpedanceResult[dq_term_option][3] << 0)); + clrsetbits_le32(&ch[0].ao.shu[0].drving[3], (0x1F << 25)|(0x1F << 20), + (uSwImpedanceResult[dq_term_option][2] << 25) | + (uSwImpedanceResult[dq_term_option][3] << 20)); + /* DQS */ + clrsetbits_le32(&ch[0].ao.shu[0].drving[0], (0x1F << 25)|(0x1F << 20), + (uSwImpedanceResult[dq_term_option][0] << 25) | + (uSwImpedanceResult[dq_term_option][1] << 20)); + clrsetbits_le32(&ch[0].ao.shu[0].drving[0], (0x1F << 15)|(0x1F << 10), + (uSwImpedanceResult[dq_term_option][0] << 15) | + (uSwImpedanceResult[dq_term_option][1] << 10)); + clrsetbits_le32(&ch[0].ao.shu[0].drving[2], (0x1F << 25)|(0x1F << 20), + (uSwImpedanceResult[dq_term_option][2] << 25) | + (uSwImpedanceResult[dq_term_option][3] << 20)); + clrsetbits_le32(&ch[0].ao.shu[0].drving[2], (0x1F << 15)|(0x1F << 10), + (uSwImpedanceResult[dq_term_option][2] << 15) | + (uSwImpedanceResult[dq_term_option][3] << 10)); + + /* CMD & CLK */ + clrsetbits_le32(&ch[0].ao.shu[0].drving[1], (0x1F << 15)|(0x1F << 10), + (uSwImpedanceResult[ca_term_option][0] << 15) | + (uSwImpedanceResult[ca_term_option][1] << 10)); + clrsetbits_le32(&ch[0].ao.shu[0].drving[1], (0x1F << 5)|(0x1F << 0), + (uSwImpedanceResult[ca_term_option][0] << 5) | + (uSwImpedanceResult[ca_term_option][1] << 0)); + clrsetbits_le32(&ch[0].ao.shu[0].drving[3], (0x1F << 15)|(0x1F << 10), + (uSwImpedanceResult[ca_term_option][2] << 15) | + (uSwImpedanceResult[ca_term_option][3] << 10)); + clrsetbits_le32(&ch[0].ao.shu[0].drving[3], (0x1F << 5)|(0x1F << 0), + (uSwImpedanceResult[ca_term_option][2] << 5) | + (uSwImpedanceResult[ca_term_option][3] << 0)); + + /* RG_TX_*RCKE_DRVP/RG_TX_*RCKE_DRVN doesn't set, so set 0xA first */ + clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[11], (0x1f << 17), + (uSwImpedanceResult[ca_term_option][0] << 17)); + clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[11], (0x1f << 22), + (uSwImpedanceResult[ca_term_option][1] << 22)); + /* DRVP[4:0] = RG_TX_ARCMD_PU_PRE<1:0>, RG_TX_ARCLK_DRVN_PRE<2:0> */ + clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[3], + SHU1_CA_CMD3_RG_TX_ARCMD_PU_PRE_MASK, + (((8 >> 3) & 0x3) << + SHU1_CA_CMD3_RG_TX_ARCMD_PU_PRE_SHIFT)); + clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[0], + SHU1_CA_CMD0_RG_TX_ARCLK_DRVN_PRE_MASK, + ((8 & 0x7) << SHU1_CA_CMD0_RG_TX_ARCLK_DRVN_PRE_SHIFT)); + + dramc_broadcast_onoff(DRAMC_BROADCAST_OFF); + clrsetbits_le32(&ch[0].phy.shu[0].ca_dll[1], + (0x1F << 16), (0x9 << 16)); + clrsetbits_le32(&ch[1].phy.shu[0].ca_dll[1], + (0x1F << 16), (0x9 << 16)); + dramc_broadcast_onoff(DRAMC_BROADCAST_ON); + + for (term_opt = 0; term_opt < 2; term_opt++) { + dramc_show("term_opt=%d, Reg: DRVP=%d, DRVN=%d, ODTN=%d\n", + term_opt, uSwImpedanceResult[term_opt][0], + uSwImpedanceResult[term_opt][1], + uSwImpedanceResult[term_opt][3]); + } + dramc_broadcast_onoff(broadcast_bak); +} + +static void enable_dramc_phy_dcm_2_channel(u8 chn, u8 bEn) +{ + u8 shu, shu_cnt = DRAM_DFS_SHUFFLE_MAX; + + if (!bEn) { + clrsetbits_le32(&ch[chn].phy.misc_cg_ctrl0, + (0x1 << 20) | (0x1 << 19) | 0x3FF << 8, + (0x0 << 20) | (0x1 << 19) | 0x3FF << 8); + + for (shu = DRAM_DFS_SHUFFLE_1; shu < shu_cnt; shu++) { + setbits_le32(&ch[chn].phy.shu[shu].b[0].dq[8], + 0x1FFF << 19); + setbits_le32(&ch[chn].phy.shu[shu].b[1].dq[8], + 0x1FFF << 19); + clrbits_le32(&ch[chn].phy.shu[shu].ca_cmd[8], + 0x1FFF << 19); + } + clrbits_le32(&ch[chn].phy.misc_cg_ctrl5, + (0x7 << 16) | (0x7 << 20)); + } +} + +void enable_dramc_phy_dcm(u8 bEn) +{ + u32 broadcast_bak = get_dramc_broadcast(); + u8 shu, shu_cnt = DRAM_DFS_SHUFFLE_MAX; + u8 chn = 0; + + dramc_broadcast_onoff(DRAMC_BROADCAST_OFF); + + for (chn = 0; chn < CHANNEL_NUM ; chn++) { + clrbits_le32(&ch[chn].phy.b[0].dll_fine_tune[1], (0x1 << 20)); + clrbits_le32(&ch[chn].phy.b[1].dll_fine_tune[1], (0x1 << 20)); + clrbits_le32(&ch[chn].phy.ca_dll_fine_tune[1], (0x1 << 20)); + + for (shu = 0; shu < shu_cnt; shu++) { + setbits_le32(&ch[chn].phy.shu[shu].b[0].dll[0], + (0x1 << 0)); + setbits_le32(&ch[chn].phy.shu[shu].b[1].dll[0], + (0x1 << 0)); + setbits_le32(&ch[chn].phy.shu[shu].ca_dll[0], + (0x1 << 0)); + } + + if (bEn) { /* DCM on */ + clrsetbits_le32(&ch[chn].ao.dramc_pd_ctrl, + (0x1 << 0) | (0x1 << 1) | (0x1 << 2) | + (0x1 << 5) | + (0x1 << 26) | (0x1 << 30) | (0x1 << 31), + (0x1 << 0) | (0x1 << 1) | (0x1 << 2) | + (0x0 << 5) | + (0x0 << 26) | (0x1 << 30) | (0x1 << 31)); + + /* CHANNEL_EMI free run */ + write32(&ch[chn].phy.misc_cg_ctrl2, 0x806003BE); + write32(&ch[chn].phy.misc_cg_ctrl2, 0x806003BF); + write32(&ch[chn].phy.misc_cg_ctrl2, 0x806003BF); + clrbits_le32(&ch[chn].phy.misc_ctrl3, (0x3 << 26)); + + for (shu = 0; shu < shu_cnt; shu++) { + setbits_le32(&ch[chn].phy.shu[shu].b[0].dq[7], + (0x7 << 17)); + setbits_le32(&ch[chn].phy.shu[shu].b[1].dq[7], + (0x7 << 17)); + setbits_le32(&ch[chn].phy.shu[shu].ca_cmd[7], + (0x7 << 17)); + } + } else { + clrsetbits_le32(&ch[chn].ao.dramc_pd_ctrl, + (0x1 << 0) | (0x1 << 1) | (0x1 << 2) | + (0x1 << 5) | (0x1 << 26) | + (0x1 << 30) | (0x1 << 31), + (0x0 << 0) | (0x0 << 1) | (0x0 << 2) | + (0x1 << 5) | (0x1 << 26) | + (0x0 << 30) | (0x0 << 31)); + + /* mem_dcm */ + write32(&ch[chn].phy.misc_cg_ctrl2, 0x8060037E); + write32(&ch[chn].phy.misc_cg_ctrl2, 0x8060037F); + write32(&ch[chn].phy.misc_cg_ctrl2, 0x8060037E); + + setbits_le32(&ch[chn].phy.misc_ctrl3, (0x3 << 26)); + + for (shu = 0; shu < shu_cnt; shu++) { + clrbits_le32(&ch[chn].phy.shu[shu].b[0].dq[7], + (0x7 << 17)); + clrbits_le32(&ch[chn].phy.shu[shu].b[1].dq[7], + (0x7 << 17)); + clrbits_le32(&ch[chn].phy.shu[shu].ca_cmd[7], + (0x7 << 17)); + } + } + } + enable_dramc_phy_dcm_2_channel(chn, bEn); + + dramc_broadcast_onoff(broadcast_bak); +} + +static void reset_delay_chain_before_calibration(void) +{ + u8 chn = 0, rank = 0; + + for (chn = 0; chn < CHANNEL_NUM; chn++) { + for (rank = 0; rank < RANK_MAX; rank++) { + clrbits_le32(&ch[chn].phy.shu[0].rk[rank].ca_cmd[0], + (0xffffff << 0)); + clrbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[0], + (0xfffffff << 0)); + clrbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[0], + (0xfffffff << 0)); + + clrbits_le32(&ch[chn].phy.shu[0].rk[rank].b[0].dq[1], + (0xf << 0)); + + clrbits_le32(&ch[chn].phy.shu[0].rk[rank].b[1].dq[1], + (0xf << 0)); + } + } +} + +void dramc_hw_gating_onoff(u8 chn, u8 u1OnOff) +{ + clrsetbits_le32(&ch[chn].ao.shuctrl2, (0x3 << 14), + (u1OnOff << 14) | (u1OnOff << 15)); + clrsetbits_le32(&ch[chn].ao.stbcal2, (0x1 << 28), (u1OnOff << 28)); + clrsetbits_le32(&ch[chn].ao.stbcal, (0x1 << 24), (u1OnOff << 24)); + clrsetbits_le32(&ch[chn].ao.stbcal, (0x1 << 22), (u1OnOff << 22)); +} + +static void dramc_rx_input_delay_tracking_init_by_freq(void) +{ + u8 u1DVS_Delay; + + u1DVS_Delay = 3; + clrsetbits_le32(&ch[0].phy.shu[0].b[0].dq[5], + (0x7 << 20), (u1DVS_Delay << 20)); + clrsetbits_le32(&ch[0].phy.shu[0].b[1].dq[5], + (0x7 << 20), (u1DVS_Delay << 20)); + clrsetbits_le32(&ch[0].phy.shu[0].b[0].dq[7], + (0x1 << 12) | (0x1 << 13), (0x0 << 12) | (0x0 << 13)); + clrsetbits_le32(&ch[0].phy.shu[0].b[1].dq[7], + (0x1 << 12) | (0x1 << 13), (0x0 << 12) | (0x0 << 13)); +} + +void apply_config_before_calibration(void) +{ + u8 shuf = 0; + + /* Clk free run */ + enable_dramc_phy_dcm(0); + + /* Set LP4 Rank0/1 CA/TX delay chain to 0 + * CA0~9 per bit delay line -> CHA_CA0 CHA_CA3 CHA_B0_DQ6 CHA_B0_DQ7 + * CHA_B0_DQ2 CHA_B0_DQ5 CHA_B0_DQ4 CHA_B0_DQ1 CHA_B0_DQ0 CHA_B0_DQ3 */ + reset_delay_chain_before_calibration(); + + /* MR4 refresh cnt set to 0x1ff (2ms update) */ + clrsetbits_le32(&ch[0].ao.shu[0].conf[3], + (0x1ff << 16), (0x1ff << 16)); + + /* The counter for Read MR4 cannot be reset + * after SREF if DRAMC no power down. */ + setbits_le32(&ch[0].ao.spcmdctrl, (0x1 << 24)); + + /* ---- ZQ CS init -------- */ + /* ZQ Calibration Time, unit: 38.46ns, tZQCAL min is 1 us. + * need to set larger than 0x1b + */ + clrsetbits_le32(&ch[0].ao.shu[0].scintv, + (0x1f << 1), (0x1b << 1)); + /* Every refresh number to issue ZQCS commands, + * only for DDR3/LPDDR2/LPDDR3/LPDDR4 + */ + for (shuf = DRAM_DFS_SHUFFLE_1; shuf < DRAM_DFS_SHUFFLE_MAX; shuf++) + setbits_le32(&ch[0].ao.shu[shuf].conf[3], (0x1ff << 0)); + + /* HW send ZQ command for both rank, disable it due to + * some dram only have 1 ZQ pin for two rank. + */ + clrbits_le32(&ch[0].ao.dramctrl, (0x1 << 18)); + + /* Disable LP4 HW ZQ */ + /* ZQCSDISB=0 */ + clrbits_le32(&ch[0].ao.spcmdctrl, (0x1 << 31)); + /* LP4 ZQCALDISB=0 */ + clrbits_le32(&ch[0].ao.spcmdctrl, (0x1 << 30)); + /* End of ZQ CS init */ + + /* CBT_MODE = NORMAL_MODE */ + clrbits_le32(&ch[0].ao.dqsoscr, (0x1 << 26)); + clrbits_le32(&ch[0].ao.dqsoscr, (0x1 << 25)); + + /* Recover write-DBI of DRAMC */ + dramc_write_dbi_onoff(DBI_OFF); + dramc_read_dbi_onoff(DBI_OFF); + + for (int chn = 0; chn < CHANNEL_NUM; chn++) { + /* disable MR4 read, REFRDIS=1 */ + setbits_le32(&ch[chn].ao.spcmdctrl, (0x1 << 29)); + setbits_le32(&ch[chn].ao.dqsoscr, (0x1 << 24)); + for (shuf = 0; shuf < DRAM_DFS_SHUFFLE_MAX; shuf++) + setbits_le32(&ch[chn].ao.shu[shuf].scintv, + (0x1 << 30)); + + clrbits_le32(&ch[chn].ao.dummy_rd, (0x1 << 7) | (0x7 << 20)); + + /* Disable HW gating tracking first, 0x1c0[31], + * need to disable both coarse tune and fine tune tracking + * or the gating delay reg won't be valid. + */ + dramc_hw_gating_onoff(chn, GATING_OFF); + + /* Disable gating debug */ + clrbits_le32(&ch[chn].ao.stbcal2, (0x1 << 28)); + } + + for (size_t r = 0; r < 2; r++) { + for (size_t b = 0; b < 2; b++) { + /* Disable RX delay tracking */ + clrbits_le32(&ch[0].phy.r[r].b[b].rxdvs[2], + (0x1 << 28)); + clrbits_le32(&ch[0].phy.r[r].b[b].rxdvs[2], + (0x1 << 23)); + + /* RX delay mux, delay vlaue from reg. */ + clrbits_le32(&ch[0].phy.r[r].b[b].rxdvs[2], + (0x3 << 30)); + } + clrbits_le32(&ch[0].phy.r0_ca_rxdvs[2], + (0x3 << 30)); + } + + for (int chn = 0; chn < CHANNEL_NUM; chn++) { + setbits_le32(&ch[chn].phy.misc_ctrl1, + (0x1 << 7) | (0x1 << 11)); + + /* Set to all-bank refresh */ + clrbits_le32(&ch[chn].ao.refctrl0, (0x1 << 18)); + + /* set MPCRK to 0, MPCRKEN alwasys set 1 */ + clrbits_le32(&ch[chn].ao.mrs, (0x3 << 24)); + setbits_le32(&ch[chn].ao.mpc_option, (0x1 << 17)); + + /* RG mode */ + clrsetbits_le32(&ch[chn].phy.b[0].dq[6], + (0x3 << 0), (0x1 << 0)); + clrsetbits_le32(&ch[chn].phy.b[1].dq[6], + (0x3 << 0), (0x1 << 0)); + clrsetbits_le32(&ch[chn].phy.ca_cmd[6], + (0x3 << 0), (0x1 << 0)); + } + + dramc_rx_input_delay_tracking_init_by_freq(); + for (int chn = 0; chn < CHANNEL_NUM; chn++) { + setbits_le32(&ch[chn].ao.dummy_rd, (0x1 << 25)); + setbits_le32(&ch[chn].ao.drsctrl, (0x1 << 0)); + + clrbits_le32(&ch[chn].ao.shu[1].drving[1], 0x1 << 31); + } +} + +void dram_calibration_all_channel(const struct sdram_params *params) +{ + for (u8 chn = 0; chn < CHANNEL_NUM; chn++) { + for (u8 rank = RANK_0; rank < RANK_MAX; rank++) { + dramc_show("start K ch:%d, rank:%d\n", chn, rank); + dramc_zq_calibration(chn, rank); + auto_refresh_switch(chn, 0); + + cmd_bus_training(chn, rank, params); + + /* Dram will be reset when finish write leveling */ + dramc_write_leveling(chn, rank, params); + + auto_refresh_switch(chn, 1); + dramc_rx_dqs_gating_cal(chn, rank); + dramc_rx_window_perbit_cal(chn, RX_WIN, rank, 0); + + dramc_tx_window_perbit_cal(chn, rank, + TX_WIN_MOVE_DQ_DQM); + dramc_tx_window_perbit_cal(chn, rank, + TX_WIN_MOVE_DQ_ONLY); + + dramc_rx_datlat_cal(chn, rank); + dramc_rx_window_perbit_cal(chn, RX_WIN, rank, 1); + } + + /* ENABLE_TX_TRACKING */ + dramc_rx_dqs_gating_post_process(chn); + dramc_dual_rank_rx_datlat_cal(chn); + } +} diff --git a/src/soc/mediatek/mt8183/emi.c b/src/soc/mediatek/mt8183/emi.c index e37fd56..8ef1613 100644 --- a/src/soc/mediatek/mt8183/emi.c +++ b/src/soc/mediatek/mt8183/emi.c @@ -13,9 +13,312 @@ * GNU General Public License for more details. */
+#include <arch/io.h> +#include <soc/addressmap.h> +#include <soc/dramc_pi_api.h> +#include <soc/dramc_register.h> #include <soc/emi.h> +#include <soc/infracfg.h> +#include <soc/spm.h> +#include <delay.h> + +struct emi_regs *emi_regs = (void *)EMI_BASE; + +void get_dram_rank_size(u64 *dram_rank_size) +{ + u32 col_bit, row_bit; + u32 shift_for_16bit = 1; /* data width = 2 bytes */ + u64 ch0_rank0_size, ch0_rank1_size, ch1_rank0_size, ch1_rank1_size; + u64 ch_rank0_size = 0, ch_rank1_size = 0; + + u32 emi_cona = read32(&emi_regs->cona); + u32 emi_conh = read32(&emi_regs->conh); + + if (emi_cona & 0x2) + shift_for_16bit = 0; /* data width = 4 bytes */ + + dram_rank_size[0] = 0; + dram_rank_size[1] = 0; + + ch0_rank0_size = (emi_conh >> 16) & 0xf; + ch0_rank1_size = (emi_conh >> 20) & 0xf; + ch1_rank0_size = (emi_conh >> 24) & 0xf; + ch1_rank1_size = (emi_conh >> 28) & 0xf; + + /* CH0 EMI */ + if (ch0_rank0_size == 0) { + /* rank 0 setting */ + col_bit = ((emi_cona >> 4) & 0x03) + 9; + row_bit = ((((emi_cona >> 24) & 0x01) << 2) + + ((emi_cona >> 12) & 0x03)) + 13; + /* data width (bytes) * 8 banks */ + ch_rank0_size = ((u64)(1 << (row_bit + col_bit))) * + ((u64)(4 >> shift_for_16bit) * 8); + } else { + ch_rank0_size = (ch0_rank0_size * 256 << 20); + } + + /* dual rank enable */ + if (0 != (emi_cona & (1 << 17))) { + if (ch0_rank1_size == 0) { + col_bit = ((emi_cona >> 6) & 0x03) + 9; + row_bit = ((((emi_cona >> 25) & 0x01) << 2) + + ((emi_cona >> 14) & 0x03)) + 13; + /* data width (bytes) * 8 banks */ + ch_rank1_size = ((u64)(1 << (row_bit + col_bit))) * + ((u64)(4 >> shift_for_16bit) * 8); + } else { + ch_rank1_size = (ch0_rank1_size * 256 << 20); + } + } + + dram_rank_size[0] = ch_rank0_size; + dram_rank_size[1] = ch_rank1_size; + + if (ch1_rank0_size == 0) { + /* rank0 setting */ + col_bit = ((emi_cona >> 20) & 0x03) + 9; + row_bit = ((((emi_conh >> 4) & 0x01) << 2) + + ((emi_cona >> 28) & 0x03)) + 13; + + /* data width (bytes) * 8 banks */ + ch_rank0_size = ((u64)(1 << (row_bit + col_bit))) * + ((u64)(4 >> shift_for_16bit) * 8); + } else { + ch_rank0_size = (ch1_rank0_size * 256 << 20); + } + + if (0 != (emi_cona & (1 << 16))) { + if (ch1_rank1_size == 0) { + col_bit = ((emi_cona >> 22) & 0x03) + 9; + row_bit = ((((emi_conh >> 5) & 0x01) << 2) + + ((emi_cona >> 30) & 0x03)) + 13; + /* data width (bytes) * 8 banks */ + ch_rank1_size = ((u64)(1 << (row_bit + col_bit))) * + ((u64)(4 >> shift_for_16bit) * 8); + } else { + ch_rank1_size = (ch1_rank1_size * 256 << 20); + } + } + + dram_rank_size[0] += ch_rank0_size; + dram_rank_size[1] += ch_rank1_size; +}
size_t sdram_size(void) { - return (size_t)4 * GiB; + size_t dram_size = 0; + u64 rank_size[RANK_MAX]; + + get_dram_rank_size(&rank_size[0]); + + for (int i = 0; i < RANK_MAX; i++) { + dram_size += rank_size[i]; + dramc_show("rank%d size:0x%llx\n", i, rank_size[i]); + } + + return dram_size; +} + +static void set_rank_info_to_conf(const struct sdram_params *params) +{ + u8 u4value = 0; + + /* CONA 17th bit 0: Disable dual rank mode + * 1: Enable dual rank mode */ + u4value = ((params->EMI_CONA_VAL & (0x1 << 17)) >> 17) ? 0 : 1; + clrsetbits_le32(&ch[0].ao.arbctl, 0x1 << 12, u4value << 12); +} + +static void set_MRR_pinmux_mapping(void) +{ + u8 chn; + u8 phy_mapping[CHANNEL_NUM][16] = { + [CHANNEL_A] = { + 1, 0, 2, 4, 3, 7, 5, 6, + 9, 8, 12, 11, 10, 15, 13, 14 + }, + + [CHANNEL_B] = { + 0, 1, 5, 6, 3, 7, 4, 2, + 9, 8, 12, 15, 11, 14, 13, 10 + } + }; + + for (chn = 0; chn < CHANNEL_NUM; chn++) { + u8 *map = phy_mapping[chn]; + write32(&ch[chn].ao.mrr_bit_mux1, + (map[0] << 0) | (map[1] << 8) | + (map[2] << 16) | (map[3] << 24)); + + write32(&ch[chn].ao.mrr_bit_mux2, + (map[4] << 0) | (map[5]<<8) | + (map[6] << 16) | (map[7] << 24)); + + write32(&ch[chn].ao.mrr_bit_mux3, + (map[8] << 0) | (map[9] << 8) | + (map[10] << 16) | (map[11]<<24)); + + write32(&ch[chn].ao.mrr_bit_mux4, + (map[12] << 0) | (map[13] << 8) | + (map[14] << 16) | (map[15] << 24)); + } +} + +static void global_option_init(const struct sdram_params *params) +{ + set_rank_info_to_conf(params); + set_MRR_pinmux_mapping(); +} + +static void emi_esl_setting1(void) +{ + dramc_broadcast_onoff(DRAMC_BROADCAST_ON); + + write32(&emi_regs->cona, 0xa053a154); + + write32(&emi_regs->conb, 0x17283544); + write32(&emi_regs->conc, 0x0a1a0b1a); + write32(&emi_regs->cond, 0x3657587a); + write32(&emi_regs->cone, 0x80400148); + write32(&emi_regs->conf, 0x00000000); + write32(&emi_regs->cong, 0x2b2b2a38); + write32(&emi_regs->conh, 0x00000000); + + write32(&emi_regs->coni, 0x00008803); + write32(&emi_regs->conm, 0x000001ff); + write32(&emi_regs->conn, 0x00000000); + write32(&emi_regs->mdct, 0x11338c17); + write32(&emi_regs->mdct_2nd, 0x00001112); + write32(&emi_regs->iocl, 0xa8a8a8a8); + write32(&emi_regs->iocl_2nd, 0x25252525); + write32(&emi_regs->iocm, 0xa8a8a8a8); + write32(&emi_regs->iocm_2nd, 0x25252525); + write32(&emi_regs->testb, 0x00060037); + write32(&emi_regs->testc, 0x38460000); + write32(&emi_regs->testd, 0x00000000); + + write32(&emi_regs->arba, 0x4020524f); + write32(&emi_regs->arbb, 0x4020504f); + write32(&emi_regs->arbc, 0xa0a050c6); + write32(&emi_regs->arbd, 0x000070cc); + write32(&emi_regs->arbe, 0x40406045); + write32(&emi_regs->arbf, 0xa0a070d5); + write32(&emi_regs->arbg, 0xa0a0504f); + write32(&emi_regs->arbh, 0xa0a0504f); + + write32(&emi_regs->arbi, 0x00007108); + write32(&emi_regs->arbi_2nd, 0x00007108); + write32(&emi_regs->slct, 0x0001ff00); + + write32(&ch[0].emi.chn_cona, 0x0400a051); + write32(&ch[0].emi.chn_conb, 0x00ff2048); + write32(&ch[0].emi.chn_conc, 0x00000000); + write32(&ch[0].emi.chn_mdct, 0x88008817); + + write32(&ch[0].emi.chn_testb, 0x00030027); + write32(&ch[0].emi.chn_testc, 0x38460002); + write32(&ch[0].emi.chn_testd, 0x00000000); + + write32(&ch[0].emi.chn_md_pre_mask, 0x00000f00); + write32(&ch[0].emi.chn_md_pre_mask_shf, 0x00000b00); + + write32(&ch[0].emi.chn_arbi, 0x20406188); + write32(&ch[0].emi.chn_arbi_2nd, 0x20406188); + + write32(&ch[0].emi.chn_arbj, 0x3719595e); + write32(&ch[0].emi.chn_arbj_2nd, 0x3719595e); + write32(&ch[0].emi.chn_arbk, 0x64f3fc79); + write32(&ch[0].emi.chn_arbk_2nd, 0x64f3fc79); + write32(&ch[0].emi.chn_slct, 0x00080888); + write32(&ch[0].emi.chn_arb_ref, 0x82410222); + + write32(&ch[0].emi.chn_emi_shf0, 0x8a228c17); + write32(&ch[0].emi.chn_rkarb0, 0x0006002f); + write32(&ch[0].emi.chn_rkarb1, 0x01010101); + write32(&ch[0].emi.chn_rkarb2, 0x10100820); + write32(&ch[0].emi.chn_eco3, 0x00000000); + + dramc_broadcast_onoff(DRAMC_BROADCAST_OFF); +} + +static void emi_esl_setting2(void) +{ + dramc_broadcast_onoff(DRAMC_BROADCAST_ON); + + write32(&ch[0].emi.chn_conc, 0x01); + write32(&emi_regs->conm, 0x05ff); + + dramc_broadcast_onoff(DRAMC_BROADCAST_OFF); +} + +static void emi_init(const struct sdram_params *params) +{ + emi_esl_setting1(); + + write32(&emi_regs->cona, params->EMI_CONA_VAL); + write32(&emi_regs->conf, params->EMI_CONF_VAL); + write32(&emi_regs->conh, params->EMI_CONH_VAL); + + for (size_t chn = CHANNEL_A; chn < CHANNEL_NUM; chn++) { + write32(&ch[chn].emi.chn_cona, params->CHN_EMI_CONA_VAL[chn]); + write32(&ch[chn].emi.chn_conc, 0); + } +} + +static void emi_init2(const struct sdram_params *params) +{ + emi_esl_setting2(); + + setbits_le32(&emi_mpu->mpu_ctrl_d0 + 0x4 * 1, 0x1 << 4); + setbits_le32(&emi_mpu->mpu_ctrl_d0 + 0x4 * 7, 0x1 << 4); + + write32(&emi_regs->bwct0, 0x0A000705); + write32(&emi_regs->bwct0_3rd, 0x0); + + /* EMI QoS 0.5 */ + write32(&emi_regs->bwct0_2nd, 0x00030023); + write32(&emi_regs->bwct0_4th, 0x00c00023); + write32(&emi_regs->bwct0_5th, 0x00240023); +} + +static void dramc_init_pre_settings(void) +{ + clrsetbits_le32(&ch[0].phy.ca_cmd[8], + (0x1 << 21) | (0x1 << 20) | (0x1 << 19) | (0x1 << 18) | + (0x1F << 8) | (0x1f << 0), + (0x1 << 19) | (0xa << 8) | (0xa << 0)); + + setbits_le32(&ch[0].phy.misc_ctrl1, (0x1 << 12)); + clrbits_le32(&ch[0].phy.misc_ctrl1, (0x1 << 13)); + setbits_le32(&ch[0].phy.misc_ctrl1, (0x1 << 31)); +} + +static void init_dram(const struct sdram_params *params) +{ + global_option_init(params); + emi_init(params); + + dramc_broadcast_onoff(DRAMC_BROADCAST_ON); + dramc_init_pre_settings(); + + dramc_sw_impedance_save_register(params); + + dramc_init(params); + emi_init2(params); +} + +static void do_calib(const struct sdram_params *params) +{ + apply_config_before_calibration(); + dram_calibration_all_channel(params); + + dramc_ac_timing_optimize(); + dramc_runtime_config(); +} + +void mt_set_emi(const struct sdram_params *params) +{ + init_dram(params); + do_calib(params); } diff --git a/src/soc/mediatek/mt8183/include/soc/addressmap.h b/src/soc/mediatek/mt8183/include/soc/addressmap.h index de7eb1f..f8edf5b 100644 --- a/src/soc/mediatek/mt8183/include/soc/addressmap.h +++ b/src/soc/mediatek/mt8183/include/soc/addressmap.h @@ -19,7 +19,6 @@ enum { MCUCFG_BASE = 0x0C530000, IO_PHYS = 0x10000000, - DDR_BASE = 0x40000000 };
enum { @@ -30,6 +29,9 @@ RGU_BASE = IO_PHYS + 0x00007000, GPT_BASE = IO_PHYS + 0x00008000, APMIXED_BASE = IO_PHYS + 0x0000C000, + EMI_BASE = IO_PHYS + 0x00219000, + EMI_MPU_BASE = IO_PHYS + 0x00226000, + DRAMC_CH_BASE = IO_PHYS + 0x00228000, UART0_BASE = IO_PHYS + 0x01002000, SPI0_BASE = IO_PHYS + 0x0100A000, SPI1_BASE = IO_PHYS + 0x01010000, diff --git a/src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h b/src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h new file mode 100644 index 0000000..08b7b78 --- /dev/null +++ b/src/soc/mediatek/mt8183/include/soc/dramc_common_mt8183.h @@ -0,0 +1,54 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DRAMC_COMMON_MT8183_H_ +#define _DRAMC_COMMON_MT8183_H_ + +enum { + CHANNEL_A = 0, + CHANNEL_B, + CHANNEL_NUM +}; + +enum { + RANK_0 = 0, + RANK_1, + RANK_MAX +}; + +enum dram_odt_type { + ODT_OFF = 0, + ODT_ON +}; + +enum { + DQ_DATA_WIDTH = 16, + DQS_BIT_NUMBER = 8, + DQS_NUMBER = (DQ_DATA_WIDTH / DQS_BIT_NUMBER) +}; + +/* + * Internal CBT mode enum + * 1. Calibration flow uses vGet_Dram_CBT_Mode to + * differentiate between mixed vs non-mixed LP4 + * 2. Declared as dram_cbt_mode[RANK_MAX] internally to + * store each rank's CBT mode type + */ +enum { + CBT_NORMAL_MODE = 0, + CBT_BYTE_MODE1 +}; + +#endif /* _DRAMC_COMMON_MT8183_H_ */ diff --git a/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h b/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h new file mode 100644 index 0000000..409086f --- /dev/null +++ b/src/soc/mediatek/mt8183/include/soc/dramc_pi_api.h @@ -0,0 +1,245 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DRAMC_PI_API_MT8183_H +#define _DRAMC_PI_API_MT8183_H + +#include <console/console.h> +#include <soc/emi.h> +#include <types.h> + +#define dramc_show(_x_...) printk(BIOS_INFO, _x_) +#if IS_ENABLED(CONFIG_DEBUG_DRAM) +#define dramc_dbg(_x_...) printk(BIOS_DEBUG, _x_) +#else +#define dramc_dbg(_x_...) +#endif + +#define ENABLE 1 +#define DISABLE 0 + +#define DATLAT_TAP_NUMBER 32 +#define DEFAULT_TEST2_1_CAL 0x55000000 +#define DEFAULT_TEST2_2_CAL 0xaa000400 + +#define MAX_CMP_CPT_WAIT_LOOP 10000 +#define TIME_OUT_CNT 100 + +#define DRAMC_BROADCAST_ON 0x1f +#define DRAMC_BROADCAST_OFF 0x0 +#define MR13_RRO 1 +#define POS_BANK_NUM 16 +#define MAX_BACKUP_REG_CNT 64 + +enum { + TEST_ISI_PATTERN = 0, + TEST_AUDIO_PATTERN, + TEST_XTALK_PATTERN, + TEST_TA1_SIMPLE, + TEST_TESTPAT4, + TEST_TESTPAT4_3, + TEST_MIX_PATTERN, + TEST_DMA, +}; + +enum dram_datlat_type { + DATLAT_USE_DEFAULT = 0, + DATLAT_USE_RX_SCAN, +}; + +enum dram_te_op { + TE_OP_WRITE_READ_CHECK = 0, + TE_OP_READ_CHECK +}; + +enum { + DBI_OFF = 0, + DBI_ON +}; + +enum { + FSP_0 = 0, + FSP_1, + FSP_MAX +}; + +enum { + DLL_MASTER_CH = CHANNEL_A, + DLL_SLAVE_CH = CHANNEL_B, +}; + +enum { + TX_DQ_DQS_MOVE_DQ_ONLY = 0, + TX_DQ_DQS_MOVE_DQM_ONLY, + TX_DQ_DQS_MOVE_DQ_DQM +}; + +enum { + MAX_CA_FINE_TUNE_DELAY = 63, + MAX_CS_FINE_TUNE_DELAY = 63, + MAX_CLK_FINE_TUNE_DELAY = 31, + CATRAINING_NUM = 6, + PASS_RANGE_NA = 0x7fff +}; + +enum { + CBT_LOW_FREQ = 0, + CBT_HIGH_FREQ = 1 +}; + +enum { + CBT_OFF = 0, + CBT_ON = 1 +}; + +enum { + GATING_OFF = 0, + GATING_ON = 1 +}; + +enum { + CKE_FIXOFF = 0, + CKE_FIXON, + CKE_DYNAMIC +}; + +enum { + RANK_SINGLE = 1, + RANK_DUAL +}; + +enum { + GATING_PATTERN_NUM = 0x23, + GATING_GOLDEND_DQSCNT = 0x4646 +}; + +enum { + IMPCAL_STAGE_DRVP = 0x1, + IMPCAL_STAGE_DRVN, + IMPCAL_STAGE_TRACKING, +}; + +enum { + DQS_GW_COARSE_STEP = 1, + DQS_GW_FINE_START = 0, + DQS_GW_FINE_END = 32, + DQS_GW_FINE_STEP = 4, + DQS_GW_FREQ_DIV = 4, + RX_DQS_CTL_LOOP = 8, + RX_DLY_DQSIENSTB_LOOP = 32 +}; + +enum { + DRAM_DFS_SHUFFLE_1 = 0, + DRAM_DFS_SHUFFLE_2, + DRAM_DFS_SHUFFLE_3, + DRAM_DFS_SHUFFLE_MAX +}; + +enum { + TYPE_DDR1 = 1, + TYPE_LPDDR2, + TYPE_LPDDR3, + TYPE_PCDDR3, + TYPE_LPDDR4, + TYPE_LPDDR4X, + TYPE_LPDDR4P +}; + +enum { + AC_TIMING_DRAM_TYPE = 0, + AC_TIMING_FREQUENCY, + AC_TIMING_DBI_ONOFF, + AC_TIMING_BYTE_MODE, + AC_TIMING_TRAS, + AC_TIMING_TRP, + AC_TIMING_TRPAB, + AC_TIMING_TRC, + AC_TIMING_TRFC, + AC_TIMING_TRFCPB, + AC_TIMING_TXP, + AC_TIMING_TRTP, + AC_TIMING_TRCD, + AC_TIMING_TWR, + AC_TIMING_TWTR, + AC_TIMING_TRRD, + AC_TIMING_TFAW, + AC_TIMING_TRTW_ODT_OFF, + AC_TIMING_TRTW_ODT_ON, + AC_TIMING_REFCNT, + AC_TIMING_REFCNT_FR_CLK, + AC_TIMING_TXREFCNT, + AC_TIMING_TZQCS, + AC_TIMING_TRTPD, + AC_TIMING_TWTPD, + AC_TIMING_TMRR2W_ODT_OFF, + AC_TIMING_TMRR2W_ODT_ON, + AC_TIMING_TRAS_05T, + AC_TIMING_TRP_05T, + AC_TIMING_TRPAB_05T, + AC_TIMING_TRC_05T, + AC_TIMING_TRFC_05T, + AC_TIMING_TRFCPB_05T, + AC_TIMING_TXP_05T, + AC_TIMING_TRTP_05T, + AC_TIMING_TRCD_05T, + AC_TIMING_TWR_05T, + AC_TIMING_TWTR_05T, + AC_TIMING_TRRD_05T, + AC_TIMING_TFAW_05T, + AC_TIMING_TRTW_05T_ODT_OFF, + AC_TIMING_TRTW_05T_ODT_ON, + AC_TIMING_TRTPD_05T, + AC_TIMING_TWTPD_05T, + AC_TIMING_XRTW2W, + AC_TIMING_XRTW2R, + AC_TIMING_XRTR2W, + AC_TIMING_XRTR2R, + AC_TIMING_DMCATRAIN_INTV, + AC_TIMING_DQSINCTL_FOR_GATING, + AC_TIMING_DATLAT, + AC_TIMING_MODE_REG_WL, + AC_TIMING_MODE_REG_RL, + AC_TIMING_ITEM_NUM +}; + +enum { + SAVE_VALUE, + RESTORE_VALUE +}; + +void dramc_init(const struct sdram_params *params); +void get_dram_rank_size(u64 *dram_rank_size); +void dramc_runtime_config(void); +void dram_calibration_all_channel(const struct sdram_params *params); +void dramc_mode_reg_write(u8 chn, u8 mr_idx, u8 value); +void dramc_engine2_init(u8 chn, u8 u1RankSel, u32 test2_1, u32 test2_2, + u8 testaudpat, u8 log2loopcount); +u32 dramc_engine2_run(u8 chn, enum dram_te_op wr, u8 testaudpat); +void dramc_engine2_end(u8 chn); +void dramc_sw_impedance_save_register(const struct sdram_params *params); +void dramc_broadcast_onoff(u32 bOnOff); +u32 get_dramc_broadcast(void); +void apply_config_before_calibration(void); +void dramc_gating_mode(u8 chn, u8 mode); +void dramc_hw_gating_onoff(u8 chn, u8 u1OnOff); +void dramc_ac_timing_optimize(void); +void cke_fix_onoff(int option, u8 chn); +void save_restore_multi_reg(u8 type, u32 **reg_addr, u32 reg_count); +u8 dramc_zq_calibration(u8 chn, u8 rank); +void dramc_mode_reg_write_by_rank(u8 chn, u8 rank, u8 mr_idx, u8 value); +void enable_dramc_phy_dcm(u8 bEn); + +#endif /* _DRAMC_PI_API_MT8183_H */ diff --git a/src/soc/mediatek/mt8183/include/soc/dramc_register.h b/src/soc/mediatek/mt8183/include/soc/dramc_register.h new file mode 100644 index 0000000..9ebb5e4 --- /dev/null +++ b/src/soc/mediatek/mt8183/include/soc/dramc_register.h @@ -0,0 +1,1446 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DRAMC_REGISTER_H_ +#define _DRAMC_REGISTER_H_ + +#include <types.h> +#include <soc/addressmap.h> + +struct dramc_no_regs_rk_counter { + uint32_t pre_standby_counter; + uint32_t pre_powerdown_counter; + uint32_t act_standby_counter; + uint32_t act_powerdown_counter; +}; + +struct dramc_nao_regs_rk { + uint32_t dqsosc_status; + uint32_t dqsosc_delta; + uint32_t dqsosc_delta2; + uint32_t rsvd_1[1]; + uint32_t current_tx_setting1; + uint32_t current_tx_setting2; + uint32_t current_tx_setting3; + uint32_t current_tx_setting4; + uint32_t dummy_rd_data[4]; + uint32_t b0_stb_max_min_dly; + uint32_t b1_stb_max_min_dly; + uint32_t b2_stb_max_min_dly; + uint32_t b3_stb_max_min_dly; + uint32_t dqsiendly; + uint32_t dqsienuidly; + uint32_t dqsienuidly_p1; + uint32_t rsvd_2[1]; + uint32_t dqs_stbcaldec_cnt1; + uint32_t dqs_stbcaldec_cnt2; + uint32_t dqs_stbcalinc_cnt1; + uint32_t dqs_stbcalinc_cnt2; + uint32_t fine_tune_dq_cal; + uint32_t dqsg_retry_flag; + uint32_t fine_tune_dqm_cal; + uint32_t rsvd_3[1]; + uint32_t dqs0_stbcal_cnt; + uint32_t dqs1_stbcal_cnt; + uint32_t dqs2_stbcal_cnt; + uint32_t dqs3_stbcal_cnt; + uint32_t b01_stb_dbg_info[16]; + uint32_t b23_stb_dbg_info[16]; +}; + +struct dramc_nao_regs { + uint32_t testmode; + uint32_t lbwdat0; + uint32_t lbwdat1; + uint32_t lbwdat2; + uint32_t lbwdat3; + uint32_t reserved0[3]; + uint32_t ckphchk; + uint32_t dmmonitor; + uint32_t reserved1[2]; + uint32_t testchip_dma1; + uint32_t reserved2[19]; + uint32_t misc_statusa; + uint32_t special_status; + uint32_t spcmdresp; + uint32_t mrr_status; + uint32_t mrr_status2; + uint32_t mrrdata0; + uint32_t mrrdata1; + uint32_t mrrdata2; + uint32_t mrrdata3; + uint32_t reserved3[1]; + uint32_t drs_status; + uint32_t reserved4[4]; + uint32_t jmeter_st; + uint32_t tcmdo1lat; + uint32_t rdqc_cmp; + uint32_t ckphchk_status; + uint32_t reserved5[16]; + uint32_t hwmrr_push2pop_cnt; + uint32_t hwmrr_status; + uint32_t hw_refrate_mon; + uint32_t reserved6[2]; + uint32_t testrpt; + uint32_t cmp_err; + uint32_t test_abit_status1; + uint32_t test_abit_status2; + uint32_t test_abit_status3; + uint32_t test_abit_status4; + uint32_t reserved7[6]; + uint32_t dqsdly0; + uint32_t dq_cal_max[8]; + uint32_t dqs_cal_min[8]; + uint32_t dqs_cal_max[8]; + uint32_t dqical0; + uint32_t dqical1; + uint32_t dqical2; + uint32_t dqical3; + uint32_t reserved8[15]; + uint32_t testchip_dma_status[34]; + uint32_t reserved9[30]; + uint32_t refresh_pop_counter; + uint32_t freerun_26m_counter; + uint32_t dramc_idle_counter; + uint32_t r2r_page_hit_counter; + uint32_t r2r_page_miss_counter; + uint32_t r2r_interbank_counter; + uint32_t r2w_page_hit_counter; + uint32_t r2w_page_miss_counter; + uint32_t r2w_interbank_counter; + uint32_t w2r_page_hit_counter; + uint32_t w2r_page_miss_counter; + uint32_t w2r_interbank_counter; + uint32_t w2w_page_hit_counter; + uint32_t w2w_page_miss_counter; + uint32_t w2w_interbank_counter; + struct dramc_no_regs_rk_counter rk_counter[3]; + uint32_t dq0_toggle_counter; + uint32_t dq1_toggle_counter; + uint32_t dq2_toggle_counter; + uint32_t dq3_toggle_counter; + uint32_t dq0_toggle_counter_r; + uint32_t dq1_toggle_counter_r; + uint32_t dq2_toggle_counter_r; + uint32_t dq3_toggle_counter_r; + uint32_t read_bytes_counter; + uint32_t write_bytes_counter; + uint32_t max_sref_req_to_ack_latency_counter; + uint32_t max_rk1_drs_long_req_to_ack_latency_counter; + uint32_t max_rk1_drs_req_to_ack_latency_counter; + uint32_t reserved10[8]; + uint32_t lat_counter_cmd[8]; + uint32_t lat_counter_aver; + uint32_t lat_counter_num; + uint32_t lat_counter_block_ale; + uint32_t reserved11[5]; + uint32_t dqssamplev; + uint32_t reserved12[1]; + uint32_t dqsgnwcnt[6]; + uint32_t toggle_cnt; + uint32_t dqs0_err_cnt; + uint32_t dq_err_cnt0; + uint32_t dqs1_err_cnt; + uint32_t dq_err_cnt1; + uint32_t dqs2_err_cnt; + uint32_t dq_err_cnt2; + uint32_t dqs3_err_cnt; + uint32_t dq_err_cnt3; + uint32_t reserved13[3]; + uint32_t iorgcnt; + uint32_t dqsg_retry_state; + uint32_t dqsg_retry_state1; + uint32_t reserved14[1]; + uint32_t impcal_status1; + uint32_t impcal_status2; + uint32_t dqdrv_status; + uint32_t cmddrv_status; + uint32_t cmddrv1; + uint32_t cmddrv2; + uint32_t reserved15[98]; + struct dramc_nao_regs_rk rk[3]; + uint32_t reserved25[192]; + uint32_t dvfs_dbg0; + uint32_t dvfs_dbg1; + uint32_t dramc_nao_regs_end; +}; + +check_member(dramc_nao_regs, testmode, 0x0000); +check_member(dramc_nao_regs, lbwdat0, 0x0004); +check_member(dramc_nao_regs, lbwdat1, 0x0008); +check_member(dramc_nao_regs, lbwdat2, 0x000c); +check_member(dramc_nao_regs, lbwdat3, 0x0010); +check_member(dramc_nao_regs, ckphchk, 0x0020); +check_member(dramc_nao_regs, dmmonitor, 0x0024); +check_member(dramc_nao_regs, testchip_dma1, 0x0030); +check_member(dramc_nao_regs, misc_statusa, 0x0080); +check_member(dramc_nao_regs, special_status, 0x0084); +check_member(dramc_nao_regs, spcmdresp, 0x0088); +check_member(dramc_nao_regs, mrr_status, 0x008c); +check_member(dramc_nao_regs, mrr_status2, 0x0090); +check_member(dramc_nao_regs, mrrdata0, 0x0094); +check_member(dramc_nao_regs, mrrdata1, 0x0098); +check_member(dramc_nao_regs, mrrdata2, 0x009c); +check_member(dramc_nao_regs, mrrdata3, 0x00a0); +check_member(dramc_nao_regs, drs_status, 0x00a8); +check_member(dramc_nao_regs, jmeter_st, 0x00bc); +check_member(dramc_nao_regs, tcmdo1lat, 0x00c0); +check_member(dramc_nao_regs, rdqc_cmp, 0x00c4); +check_member(dramc_nao_regs, ckphchk_status, 0x00c8); +check_member(dramc_nao_regs, hwmrr_push2pop_cnt, 0x010c); +check_member(dramc_nao_regs, hwmrr_status, 0x0110); +check_member(dramc_nao_regs, testrpt, 0x0120); +check_member(dramc_nao_regs, cmp_err, 0x0124); +check_member(dramc_nao_regs, test_abit_status1, 0x0128); +check_member(dramc_nao_regs, test_abit_status2, 0x012c); +check_member(dramc_nao_regs, test_abit_status3, 0x0130); +check_member(dramc_nao_regs, test_abit_status4, 0x0134); +check_member(dramc_nao_regs, dqsdly0, 0x0150); +check_member(dramc_nao_regs, dq_cal_max[0], 0x0154); +check_member(dramc_nao_regs, dqs_cal_min[0], 0x0174); +check_member(dramc_nao_regs, dqs_cal_max[0], 0x0194); +check_member(dramc_nao_regs, dqical0, 0x01b4); +check_member(dramc_nao_regs, dqical1, 0x01b8); +check_member(dramc_nao_regs, dqical2, 0x01bc); +check_member(dramc_nao_regs, dqical3, 0x01c0); +check_member(dramc_nao_regs, testchip_dma_status[0], 0x0200); +check_member(dramc_nao_regs, refresh_pop_counter, 0x0300); +check_member(dramc_nao_regs, freerun_26m_counter, 0x0304); +check_member(dramc_nao_regs, dramc_idle_counter, 0x0308); +check_member(dramc_nao_regs, r2r_page_hit_counter, 0x030c); +check_member(dramc_nao_regs, r2r_page_miss_counter, 0x0310); +check_member(dramc_nao_regs, r2r_interbank_counter, 0x0314); +check_member(dramc_nao_regs, r2w_page_hit_counter, 0x0318); +check_member(dramc_nao_regs, r2w_page_miss_counter, 0x031c); +check_member(dramc_nao_regs, r2w_interbank_counter, 0x0320); +check_member(dramc_nao_regs, w2r_page_hit_counter, 0x0324); +check_member(dramc_nao_regs, w2r_page_miss_counter, 0x0328); +check_member(dramc_nao_regs, w2r_interbank_counter, 0x032c); +check_member(dramc_nao_regs, w2w_page_hit_counter, 0x0330); +check_member(dramc_nao_regs, w2w_page_miss_counter, 0x0334); +check_member(dramc_nao_regs, w2w_interbank_counter, 0x0338); +check_member(dramc_nao_regs, dq0_toggle_counter, 0x036c); +check_member(dramc_nao_regs, dq1_toggle_counter, 0x0370); +check_member(dramc_nao_regs, dq2_toggle_counter, 0x0374); +check_member(dramc_nao_regs, dq3_toggle_counter, 0x0378); +check_member(dramc_nao_regs, dq0_toggle_counter_r, 0x037c); +check_member(dramc_nao_regs, dq1_toggle_counter_r, 0x0380); +check_member(dramc_nao_regs, dq2_toggle_counter_r, 0x0384); +check_member(dramc_nao_regs, dq3_toggle_counter_r, 0x0388); +check_member(dramc_nao_regs, read_bytes_counter, 0x038c); +check_member(dramc_nao_regs, write_bytes_counter, 0x0390); +check_member(dramc_nao_regs, dqssamplev, 0x0400); +check_member(dramc_nao_regs, dqsgnwcnt[0], 0x0408); +check_member(dramc_nao_regs, toggle_cnt, 0x0420); +check_member(dramc_nao_regs, dqs0_err_cnt, 0x0424); +check_member(dramc_nao_regs, dq_err_cnt0, 0x0428); +check_member(dramc_nao_regs, dqs1_err_cnt, 0x042c); +check_member(dramc_nao_regs, dq_err_cnt1, 0x0430); +check_member(dramc_nao_regs, dqs2_err_cnt, 0x0434); +check_member(dramc_nao_regs, dq_err_cnt2, 0x0438); +check_member(dramc_nao_regs, dqs3_err_cnt, 0x043c); +check_member(dramc_nao_regs, dq_err_cnt3, 0x0440); +check_member(dramc_nao_regs, iorgcnt, 0x0450); +check_member(dramc_nao_regs, dqsg_retry_state, 0x0454); +check_member(dramc_nao_regs, dqsg_retry_state1, 0x0458); +check_member(dramc_nao_regs, impcal_status1, 0x0460); +check_member(dramc_nao_regs, impcal_status2, 0x0464); +check_member(dramc_nao_regs, dqdrv_status, 0x0468); +check_member(dramc_nao_regs, cmddrv_status, 0x046c); +check_member(dramc_nao_regs, cmddrv1, 0x0470); +check_member(dramc_nao_regs, cmddrv2, 0x0474); + +struct dramc_ao_regs_rk { + uint32_t dqsosc; + uint32_t rsvd_1[5]; + uint32_t dummy_rd_wdata0; + uint32_t dummy_rd_wdata1; + uint32_t dummy_rd_wdata2; + uint32_t dummy_rd_wdata3; + uint32_t dummy_rd_adr; + uint32_t dummy_rd_bk; + uint32_t pre_tdqsck[12]; + uint32_t rsvd_2[40]; +}; + +struct dramc_ao_regs_shu_rk { + uint32_t dqsctl; + uint32_t dqsien; + uint32_t dqscal; + uint32_t fine_tune; + uint32_t dqsosc; + uint32_t rsvd_1[2]; + uint32_t selph_odten0; + uint32_t selph_odten1; + uint32_t selph_dqsg0; + uint32_t selph_dqsg1; + uint32_t selph_dq[4]; + uint32_t rsvd_2[1]; + uint32_t dqs2dq_cal1; + uint32_t dqs2dq_cal2; + uint32_t dqs2dq_cal3; + uint32_t dqs2dq_cal4; + uint32_t dqs2dq_cal5; + uint32_t rsvd_3[43]; +}; + +struct dramc_ao_regs { + uint32_t ddrconf0; + uint32_t dramctrl; + uint32_t misctl0; + uint32_t perfctl0; + uint32_t arbctl; + uint32_t reserved0[2]; + uint32_t rstmask; + uint32_t padctrl; + uint32_t ckectrl; + uint32_t drsctrl; + uint32_t reserved1[2]; + uint32_t rkcfg; + uint32_t dramc_pd_ctrl; + uint32_t clkar; + uint32_t clkctrl; + uint32_t selfref_hwsave_flag; + uint32_t srefctrl; + uint32_t refctrl0; + uint32_t refctrl1; + uint32_t refratre_filter; + uint32_t zqcs; + uint32_t mrs; + uint32_t spcmd; + uint32_t spcmdctrl; + uint32_t ppr_ctrl; + uint32_t mpc_option; + uint32_t refque_cnt; + uint32_t hw_mrr_fun; + uint32_t mrr_bit_mux1; + uint32_t mrr_bit_mux2; + uint32_t mrr_bit_mux3; + uint32_t mrr_bit_mux4; + uint32_t reserved2[1]; + uint32_t test2_5; + uint32_t test2_0; + uint32_t test2_1; + uint32_t test2_2; + uint32_t test2_3; + uint32_t test2_4; + uint32_t wdt_dbg_signal; + uint32_t reserved3[1]; + uint32_t lbtest; + uint32_t catraining1; + uint32_t catraining2; + uint32_t reserved4[1]; + uint32_t write_lev; + uint32_t mr_golden; + uint32_t slp4_testmode; + uint32_t dqsoscr; + uint32_t reserved5[1]; + uint32_t dummy_rd; + uint32_t shuctrl; + uint32_t shuctrl1; + uint32_t shuctrl2; + uint32_t shuctrl3; + uint32_t shustatus; + uint32_t reserved6[70]; + uint32_t stbcal; + uint32_t stbcal1; + uint32_t stbcal2; + uint32_t eyescan; + uint32_t dvfsdll; + uint32_t reserved7[1]; + uint32_t pre_tdqsck[4]; + uint32_t reserved8[1]; + uint32_t impcal; + uint32_t impedamce_ctrl1; + uint32_t impedamce_ctrl2; + uint32_t impedamce_ctrl3; + uint32_t impedamce_ctrl4; + uint32_t dramc_dbg_sel1; + uint32_t dramc_dbg_sel2; + uint32_t rsvd_10[46]; + struct dramc_ao_regs_rk rk[3]; + uint32_t rsvd_16[64]; + struct { + uint32_t rsvd0[64]; + uint32_t actim[7]; + uint32_t actim_xrt; + uint32_t ac_time_05t; + uint32_t ac_derating0; + uint32_t ac_derating1; + uint32_t rsvd1[1]; + uint32_t ac_derating_05t; + uint32_t rsvd2[3]; + uint32_t conf[4]; + uint32_t stbcal; + uint32_t dqsoscthrd; + uint32_t rankctl; + uint32_t ckectrl; + uint32_t odtctrl; + uint32_t impcal1; + uint32_t dqsosc_prd; + uint32_t dqsoscr; + uint32_t dqsoscr2; + uint32_t rodtenstb; + uint32_t pipe; + uint32_t test1; + uint32_t selph_ca1; + uint32_t selph_ca2; + uint32_t selph_ca3; + uint32_t selph_ca4; + uint32_t selph_ca5; + uint32_t selph_ca6; + uint32_t selph_ca7; + uint32_t selph_ca8; + uint32_t selph_dqs0; + uint32_t selph_dqs1; + uint32_t drving[6]; + uint32_t wodt; + uint32_t dqsg; + uint32_t scintv; + uint32_t misc; + uint32_t dqs2dq_tx; + uint32_t hwset_mr2; + uint32_t hwset_mr13; + uint32_t hwset_vrcg; + uint32_t rsvd3[72]; + union { + struct dramc_ao_regs_shu_rk rk[3]; + struct { + uint32_t rsvd_63[149]; + uint32_t dqsg_retry; + }; + }; + } shu[4]; + uint32_t dramc_ao_regs_end; +}; + +check_member(dramc_ao_regs, ddrconf0, 0x0000); +check_member(dramc_ao_regs, dramctrl, 0x0004); +check_member(dramc_ao_regs, misctl0, 0x0008); +check_member(dramc_ao_regs, perfctl0, 0x000c); +check_member(dramc_ao_regs, arbctl, 0x0010); +check_member(dramc_ao_regs, rstmask, 0x001c); +check_member(dramc_ao_regs, padctrl, 0x0020); +check_member(dramc_ao_regs, ckectrl, 0x0024); +check_member(dramc_ao_regs, drsctrl, 0x0028); +check_member(dramc_ao_regs, rkcfg, 0x0034); +check_member(dramc_ao_regs, dramc_pd_ctrl, 0x0038); +check_member(dramc_ao_regs, clkar, 0x003c); +check_member(dramc_ao_regs, clkctrl, 0x0040); +check_member(dramc_ao_regs, selfref_hwsave_flag, 0x0044); +check_member(dramc_ao_regs, srefctrl, 0x0048); +check_member(dramc_ao_regs, refctrl0, 0x004c); +check_member(dramc_ao_regs, refctrl1, 0x0050); +check_member(dramc_ao_regs, refratre_filter, 0x0054); +check_member(dramc_ao_regs, zqcs, 0x0058); +check_member(dramc_ao_regs, mrs, 0x005c); +check_member(dramc_ao_regs, spcmd, 0x0060); +check_member(dramc_ao_regs, spcmdctrl, 0x0064); +check_member(dramc_ao_regs, ppr_ctrl, 0x0068); +check_member(dramc_ao_regs, mpc_option, 0x006c); +check_member(dramc_ao_regs, refque_cnt, 0x0070); +check_member(dramc_ao_regs, hw_mrr_fun, 0x0074); +check_member(dramc_ao_regs, mrr_bit_mux1, 0x0078); +check_member(dramc_ao_regs, mrr_bit_mux2, 0x007c); +check_member(dramc_ao_regs, mrr_bit_mux3, 0x0080); +check_member(dramc_ao_regs, mrr_bit_mux4, 0x0084); +check_member(dramc_ao_regs, test2_5, 0x008c); +check_member(dramc_ao_regs, test2_0, 0x0090); +check_member(dramc_ao_regs, test2_1, 0x0094); +check_member(dramc_ao_regs, test2_2, 0x0098); +check_member(dramc_ao_regs, test2_3, 0x009c); +check_member(dramc_ao_regs, test2_4, 0x00a0); +check_member(dramc_ao_regs, wdt_dbg_signal, 0x00a4); +check_member(dramc_ao_regs, lbtest, 0x00ac); +check_member(dramc_ao_regs, catraining1, 0x00b0); +check_member(dramc_ao_regs, catraining2, 0x00b4); +check_member(dramc_ao_regs, write_lev, 0x00bc); +check_member(dramc_ao_regs, mr_golden, 0x00c0); +check_member(dramc_ao_regs, slp4_testmode, 0x00c4); +check_member(dramc_ao_regs, dqsoscr, 0x00c8); +check_member(dramc_ao_regs, dummy_rd, 0x00d0); +check_member(dramc_ao_regs, shuctrl, 0x00d4); +check_member(dramc_ao_regs, shuctrl1, 0x00d8); +check_member(dramc_ao_regs, shuctrl2, 0x00dc); +check_member(dramc_ao_regs, shuctrl3, 0x00e0); +check_member(dramc_ao_regs, shustatus, 0x00e4); +check_member(dramc_ao_regs, stbcal, 0x0200); +check_member(dramc_ao_regs, stbcal1, 0x0204); +check_member(dramc_ao_regs, stbcal2, 0x0208); +check_member(dramc_ao_regs, eyescan, 0x020c); +check_member(dramc_ao_regs, dvfsdll, 0x0210); +check_member(dramc_ao_regs, pre_tdqsck[0], 0x0218); +check_member(dramc_ao_regs, pre_tdqsck[1], 0x021c); +check_member(dramc_ao_regs, pre_tdqsck[2], 0x0220); +check_member(dramc_ao_regs, pre_tdqsck[3], 0x0224); +check_member(dramc_ao_regs, impcal, 0x022c); +check_member(dramc_ao_regs, impedamce_ctrl1, 0x0230); +check_member(dramc_ao_regs, impedamce_ctrl2, 0x0234); +check_member(dramc_ao_regs, impedamce_ctrl3, 0x0238); +check_member(dramc_ao_regs, impedamce_ctrl4, 0x023c); +check_member(dramc_ao_regs, dramc_dbg_sel1, 0x0240); +check_member(dramc_ao_regs, dramc_dbg_sel2, 0x0244); +check_member(dramc_ao_regs, shu[0].actim[0], 0x0800); +check_member(dramc_ao_regs, shu[0].actim_xrt, 0x081c); +check_member(dramc_ao_regs, shu[0].ac_time_05t, 0x0820); +check_member(dramc_ao_regs, shu[0].ac_derating0, 0x0824); +check_member(dramc_ao_regs, shu[0].ac_derating1, 0x0828); +check_member(dramc_ao_regs, shu[0].ac_derating_05t, 0x0830); +check_member(dramc_ao_regs, shu[0].conf[0], 0x0840); +check_member(dramc_ao_regs, shu[0].rankctl, 0x0858); +check_member(dramc_ao_regs, shu[0].ckectrl, 0x085c); +check_member(dramc_ao_regs, shu[0].odtctrl, 0x0860); +check_member(dramc_ao_regs, shu[0].impcal1, 0x0864); +check_member(dramc_ao_regs, shu[0].dqsosc_prd, 0x0868); +check_member(dramc_ao_regs, shu[0].dqsoscr, 0x086c); +check_member(dramc_ao_regs, shu[0].dqsoscr2, 0x0870); +check_member(dramc_ao_regs, shu[0].rodtenstb, 0x0874); +check_member(dramc_ao_regs, shu[0].pipe, 0x0878); +check_member(dramc_ao_regs, shu[0].test1, 0x087c); +check_member(dramc_ao_regs, shu[0].selph_ca1, 0x0880); +check_member(dramc_ao_regs, shu[0].selph_dqs0, 0x08a0); +check_member(dramc_ao_regs, shu[0].selph_dqs1, 0x08a4); +check_member(dramc_ao_regs, shu[0].drving[0], 0x08a8); +check_member(dramc_ao_regs, shu[0].wodt, 0x08c0); +check_member(dramc_ao_regs, shu[0].dqsg, 0x08c4); +check_member(dramc_ao_regs, shu[0].scintv, 0x08c8); +check_member(dramc_ao_regs, shu[0].misc, 0x08cc); +check_member(dramc_ao_regs, shu[0].dqs2dq_tx, 0x08d0); +check_member(dramc_ao_regs, shu[0].hwset_mr2, 0x08d4); +check_member(dramc_ao_regs, shu[0].hwset_mr13, 0x08d8); +check_member(dramc_ao_regs, shu[0].hwset_vrcg, 0x08dc); +check_member(dramc_ao_regs, shu[0].rk[0].dqsctl, 0x0A00); +check_member(dramc_ao_regs, shu[0].dqsg_retry, 0x0c54); +check_member(dramc_ao_regs, shu[1].dqsg_retry, 0x1254); +check_member(dramc_ao_regs, shu[2].dqsg_retry, 0x1854); +check_member(dramc_ao_regs, shu[3].dqsg_retry, 0x1e54); + +struct dramc_ddrphy_regs_misc_stberr_rk { + uint32_t r; + uint32_t f; +}; + +struct dramc_ddrphy_regs_shu_rk { + struct { + uint32_t dq[8]; + uint32_t rsvd_20[12]; + } b[2]; + uint32_t ca_cmd[10]; + uint32_t rsvd_22[14]; +}; + +struct dramc_ddrphy_ao_regs { + uint32_t pll1; + uint32_t pll2; + uint32_t pll3; + uint32_t pll4; + uint32_t pll5; + uint32_t pll6; + uint32_t pll7; + uint32_t pll8; + uint32_t pll9; + uint32_t pll10; + uint32_t pll11; + uint32_t pll12; + uint32_t pll13; + uint32_t pll14; + uint32_t pll15; + uint32_t pll16; + uint32_t reserved0[16]; + struct { + uint32_t dll_fine_tune[6]; + uint32_t dq[10]; + uint32_t _rsvd_0[4]; + uint32_t tx_mck; + uint32_t _rsvd_1[11]; + } b[2]; + uint32_t ca_dll_fine_tune[6]; + uint32_t ca_cmd[11]; + uint32_t rfu_0x1c4; + uint32_t rfu_0x1c8; + uint32_t rfu_0x1cc; + uint32_t ca_tx_mck; + uint32_t reserved3[11]; + uint32_t misc_extlb[24]; + uint32_t dvfs_emi_clk; + uint32_t misc_vref_ctrl; + uint32_t misc_imp_ctrl0; + uint32_t misc_imp_ctrl1; + uint32_t misc_shu_opt; + uint32_t misc_spm_ctrl0; + uint32_t misc_spm_ctrl1; + uint32_t misc_spm_ctrl2; + uint32_t misc_spm_ctrl3; + uint32_t misc_cg_ctrl0; + uint32_t misc_cg_ctrl1; + uint32_t misc_cg_ctrl2; + uint32_t misc_cg_ctrl3; + uint32_t misc_cg_ctrl4; + uint32_t misc_cg_ctrl5; + uint32_t misc_ctrl0; + uint32_t misc_ctrl1; + uint32_t misc_ctrl2; + uint32_t misc_ctrl3; + uint32_t misc_ctrl4; + uint32_t misc_ctrl5; + uint32_t misc_extlb_rx[21]; + uint32_t ckmux_sel; + uint32_t reserved4[129]; + uint32_t misc_stberr_rk0_r; + uint32_t misc_stberr_rk0_f; + uint32_t misc_stberr_rk1_r; + uint32_t misc_stberr_rk1_f; + uint32_t misc_stberr_rk2_r; + uint32_t misc_stberr_rk2_f; + uint32_t reserved5[46]; + uint32_t misc_rxdvs[3]; + uint32_t rfu_0x5ec; + uint32_t b0_rxdvs[2]; + uint32_t rfu_0x5f8; + uint32_t rfu_0x5fc; + union { + struct { + struct { + uint32_t rxdvs[8]; + uint32_t _rsvd[24]; + } b[2]; + uint32_t rxdvs[10]; + uint32_t _rsvd_b[54]; + } r[3]; + struct { + uint32_t rsvd_2[28]; + uint32_t b1_rxdvs[2]; + uint32_t rsvd_3[30]; + uint32_t ca_rxdvs0; + uint32_t ca_rxdvs1; + uint32_t rsvd_4[2]; + uint32_t r0_ca_rxdvs[10]; + }; + }; + + struct { + struct { + uint32_t dq[13]; + uint32_t dll[2]; + uint32_t rsvd_16[17]; + } b[2]; + uint32_t ca_cmd[13]; + uint32_t ca_dll[2]; + uint32_t rsvd_18[17]; + uint32_t pll[16]; + uint32_t rsvd_19[4]; + uint32_t pll20; + uint32_t pll21; + uint32_t rsvd_20[6]; + uint32_t misc0; + uint32_t rsvd_21[3]; + struct dramc_ddrphy_regs_shu_rk rk[3]; + } shu[4]; +}; + +check_member(dramc_ddrphy_ao_regs, pll1, 0x0000); +check_member(dramc_ddrphy_ao_regs, b[0].dll_fine_tune[0], 0x0080); +check_member(dramc_ddrphy_ao_regs, b[0].dq[0], 0x0098); +check_member(dramc_ddrphy_ao_regs, b[0].tx_mck, 0x00d0); +check_member(dramc_ddrphy_ao_regs, ca_dll_fine_tune[0], 0x0180); +check_member(dramc_ddrphy_ao_regs, ca_cmd[0], 0x0198); +check_member(dramc_ddrphy_ao_regs, ca_tx_mck, 0x01d0); +check_member(dramc_ddrphy_ao_regs, misc_extlb[0], 0x0200); +check_member(dramc_ddrphy_ao_regs, dvfs_emi_clk, 0x0260); +check_member(dramc_ddrphy_ao_regs, misc_vref_ctrl, 0x0264); +check_member(dramc_ddrphy_ao_regs, misc_imp_ctrl0, 0x0268); +check_member(dramc_ddrphy_ao_regs, misc_imp_ctrl1, 0x026c); +check_member(dramc_ddrphy_ao_regs, misc_shu_opt, 0x0270); +check_member(dramc_ddrphy_ao_regs, misc_spm_ctrl0, 0x0274); +check_member(dramc_ddrphy_ao_regs, misc_spm_ctrl1, 0x0278); +check_member(dramc_ddrphy_ao_regs, misc_spm_ctrl2, 0x027c); +check_member(dramc_ddrphy_ao_regs, misc_spm_ctrl3, 0x0280); +check_member(dramc_ddrphy_ao_regs, misc_cg_ctrl0, 0x0284); +check_member(dramc_ddrphy_ao_regs, misc_cg_ctrl1, 0x0288); +check_member(dramc_ddrphy_ao_regs, misc_cg_ctrl2, 0x028c); +check_member(dramc_ddrphy_ao_regs, misc_cg_ctrl3, 0x0290); +check_member(dramc_ddrphy_ao_regs, misc_cg_ctrl4, 0x0294); +check_member(dramc_ddrphy_ao_regs, misc_cg_ctrl5, 0x0298); +check_member(dramc_ddrphy_ao_regs, misc_ctrl0, 0x029c); +check_member(dramc_ddrphy_ao_regs, misc_ctrl1, 0x02a0); +check_member(dramc_ddrphy_ao_regs, misc_ctrl2, 0x02a4); +check_member(dramc_ddrphy_ao_regs, misc_ctrl3, 0x02a8); +check_member(dramc_ddrphy_ao_regs, misc_ctrl4, 0x02ac); +check_member(dramc_ddrphy_ao_regs, misc_ctrl5, 0x02b0); +check_member(dramc_ddrphy_ao_regs, misc_extlb_rx[0], 0x02b4); +check_member(dramc_ddrphy_ao_regs, ckmux_sel, 0x0308); +check_member(dramc_ddrphy_ao_regs, misc_rxdvs[0], 0x05e0); +check_member(dramc_ddrphy_ao_regs, misc_rxdvs[1], 0x05e4); +check_member(dramc_ddrphy_ao_regs, misc_rxdvs[2], 0x05e8); +check_member(dramc_ddrphy_ao_regs, rfu_0x5ec, 0x05ec); +check_member(dramc_ddrphy_ao_regs, b0_rxdvs[0], 0x05f0); +check_member(dramc_ddrphy_ao_regs, r[0].b[0].rxdvs[0], 0x0600); +check_member(dramc_ddrphy_ao_regs, b1_rxdvs[0], 0x0670); +check_member(dramc_ddrphy_ao_regs, r[0].b[1].rxdvs[0], 0x0680); +check_member(dramc_ddrphy_ao_regs, ca_rxdvs0, 0x06F0); +check_member(dramc_ddrphy_ao_regs, r0_ca_rxdvs[0], 0x0700); +check_member(dramc_ddrphy_ao_regs, r[1].b[1].rxdvs[0], 0x0880); +check_member(dramc_ddrphy_ao_regs, r[1].rxdvs[0], 0x0900); +check_member(dramc_ddrphy_ao_regs, shu[0].b[0].dq[0], 0x0c00); +check_member(dramc_ddrphy_ao_regs, shu[0].b[1].dq[6], 0x0C98); +check_member(dramc_ddrphy_ao_regs, shu[0].ca_cmd[0], 0x0d00); +check_member(dramc_ddrphy_ao_regs, shu[0].ca_dll[0], 0x0d34); +check_member(dramc_ddrphy_ao_regs, shu[0].pll[0], 0x0d80); +check_member(dramc_ddrphy_ao_regs, shu[0].misc0, 0x0DF0); +check_member(dramc_ddrphy_ao_regs, shu[0].rk[0].b[0].dq[0], 0x0e00); +check_member(dramc_ddrphy_ao_regs, shu[0].rk[0].ca_cmd[9], 0x0ec4); +check_member(dramc_ddrphy_ao_regs, shu[0].rk[1].b[0].dq[0], 0x0f00); +check_member(dramc_ddrphy_ao_regs, shu[0].rk[1].ca_cmd[9], 0x0fc4); +check_member(dramc_ddrphy_ao_regs, shu[0].rk[2].b[0].dq[0], 0x1000); +check_member(dramc_ddrphy_ao_regs, shu[0].rk[2].ca_cmd[9], 0x10c4); +check_member(dramc_ddrphy_ao_regs, shu[2].b[0].dq[0], 0x1600); +check_member(dramc_ddrphy_ao_regs, shu[2].b[1].dq[0], 0x1680); +check_member(dramc_ddrphy_ao_regs, shu[2].ca_cmd[0], 0x1700); +check_member(dramc_ddrphy_ao_regs, shu[2].ca_dll[0], 0x1734); +check_member(dramc_ddrphy_ao_regs, shu[2].pll[0], 0x1780); +check_member(dramc_ddrphy_ao_regs, shu[2].misc0, 0x17F0); +check_member(dramc_ddrphy_ao_regs, shu[2].rk[0].b[0].dq[0], 0x1800); +check_member(dramc_ddrphy_ao_regs, shu[2].rk[0].ca_cmd[0], 0x18A0); +check_member(dramc_ddrphy_ao_regs, shu[2].rk[1].b[0].dq[0], 0x1900); +check_member(dramc_ddrphy_ao_regs, shu[2].rk[1].ca_cmd[0], 0x19A0); +check_member(dramc_ddrphy_ao_regs, shu[2].rk[2].b[0].dq[0], 0x1A00); +check_member(dramc_ddrphy_ao_regs, shu[2].rk[2].ca_cmd[0], 0x1AA0); +check_member(dramc_ddrphy_ao_regs, shu[3].ca_cmd[0], 0x1C00); +check_member(dramc_ddrphy_ao_regs, shu[3].pll[0], 0x1C80); +check_member(dramc_ddrphy_ao_regs, shu[3].pll20, 0x1CD0); +check_member(dramc_ddrphy_ao_regs, shu[3].misc0, 0x1CF0); +check_member(dramc_ddrphy_ao_regs, shu[3].rk[0].ca_cmd[9], 0x1DC4); +check_member(dramc_ddrphy_ao_regs, shu[3].rk[1].ca_cmd[9], 0x1EC4); +check_member(dramc_ddrphy_ao_regs, shu[3].rk[2].ca_cmd[9], 0x1FC4); + +struct dramc_ddrphy_nao_regs { + uint32_t misc_sta_extlb[3]; + uint32_t reserved0[29]; + uint32_t misc_dq_rxdly_trro[32]; + uint32_t misc_ca_rxdly_trro[32]; + uint32_t misc_dqo1; + uint32_t misc_cao1; + uint32_t misc_ad_rx_dq_o1; + uint32_t misc_ad_rx_cmd_o1; + uint32_t misc_phy_rgs_dq; + uint32_t misc_phy_rgs_cmd; + uint32_t misc_phy_stben_b0; + uint32_t misc_phy_stben_b1; + uint32_t misc_phy_rgs_stben_cmd; + uint32_t dramc_ddrphy_nao_regs_end; +}; + +check_member(dramc_ddrphy_nao_regs, misc_sta_extlb[0], 0x0); +check_member(dramc_ddrphy_nao_regs, misc_dq_rxdly_trro[0], 0x080); +check_member(dramc_ddrphy_nao_regs, misc_dqo1, 0x0180); +check_member(dramc_ddrphy_nao_regs, misc_cao1, 0x0184); +check_member(dramc_ddrphy_nao_regs, misc_phy_rgs_dq, 0x0190); +check_member(dramc_ddrphy_nao_regs, misc_phy_rgs_cmd, 0x0194); +check_member(dramc_ddrphy_nao_regs, misc_phy_stben_b0, 0x0198); +check_member(dramc_ddrphy_nao_regs, misc_phy_rgs_stben_cmd, 0x01A0); + +struct emi_regs { + uint32_t cona; + uint32_t reserved0[1]; + uint32_t conb; + uint32_t reserved1[1]; + uint32_t conc; + uint32_t reserved2[1]; + uint32_t cond; + uint32_t reserved3[1]; + uint32_t cone; + uint32_t reserved4[1]; + uint32_t conf; + uint32_t reserved5[1]; + uint32_t cong; + uint32_t reserved6[1]; + uint32_t conh; + uint32_t conh_2nd; + uint32_t coni; + uint32_t reserved7[1]; + uint32_t conj; + uint32_t reserved8[5]; + uint32_t conm; + uint32_t reserved9[1]; + uint32_t conn; + uint32_t reserved10[1]; + uint32_t cono; + uint32_t reserved11[1]; + uint32_t mdct; + uint32_t mdct_2nd; + uint32_t reserved12[20]; + uint32_t iocl; + uint32_t iocl_2nd; + uint32_t iocm; + uint32_t iocm_2nd; + uint32_t reserved13[2]; + uint32_t testb; + uint32_t reserved14[1]; + uint32_t testc; + uint32_t reserved15[1]; + uint32_t testd; + uint32_t reserved16[1]; + uint32_t arba; + uint32_t reserved17[1]; + uint32_t arbb; + uint32_t reserved18[1]; + uint32_t arbc; + uint32_t reserved19[1]; + uint32_t arbd; + uint32_t reserved20[1]; + uint32_t arbe; + uint32_t reserved21[1]; + uint32_t arbf; + uint32_t reserved22[1]; + uint32_t arbg; + uint32_t reserved23[1]; + uint32_t arbh; + uint32_t reserved24[1]; + uint32_t arbi; + uint32_t arbi_2nd; + uint32_t reserved25[2]; + uint32_t arbk; + uint32_t arbk_2nd; + uint32_t slct; + uint32_t reserved26[1]; + uint32_t mpud_st[32]; + uint32_t reserved27[4]; + uint32_t mpus; + uint32_t reserved28[1]; + uint32_t mput; + uint32_t mput_2nd; + uint32_t d_st2[32]; + uint32_t reserved29[96]; + uint32_t bmen; + uint32_t bstp; + uint32_t bcnt; + uint32_t reserved30[1]; + uint32_t tact; + uint32_t reserved31[1]; + uint32_t tsct; + uint32_t reserved32[1]; + uint32_t wact; + uint32_t reserved33[1]; + uint32_t wsct; + uint32_t reserved34[1]; + uint32_t bact; + uint32_t reserved35[1]; + uint32_t bsct; + uint32_t reserved36[1]; + uint32_t msel; + uint32_t reserved37[1]; + uint32_t tsct2; + uint32_t reserved38[1]; + uint32_t tsct3; + uint32_t reserved39[1]; + uint32_t wsct2; + uint32_t reserved40[1]; + uint32_t wsct3; + uint32_t wsct4; + uint32_t msel2; + uint32_t reserved41[1]; + uint32_t msel3; + uint32_t reserved42[1]; + uint32_t msel4; + uint32_t reserved43[1]; + uint32_t msel5; + uint32_t reserved44[1]; + uint32_t msel6; + uint32_t reserved45[1]; + uint32_t msel7; + uint32_t reserved46[1]; + uint32_t msel8; + uint32_t reserved47[1]; + uint32_t msel9; + uint32_t reserved48[1]; + uint32_t msel10; + uint32_t reserved49[1]; + uint32_t bmid0; + uint32_t bmid1; + uint32_t bmid2; + uint32_t bmid3; + uint32_t bmid4; + uint32_t bmid5; + uint32_t bmid6; + uint32_t bmid7; + uint32_t bmid8; + uint32_t bmid9; + uint32_t bmid10; + uint32_t reserved50[1]; + uint32_t bmen1; + uint32_t reserved51[1]; + uint32_t bmen2; + uint32_t reserved52[3]; + uint32_t bmrw0; + uint32_t bmrw1; + uint32_t ttype1; + uint32_t reserved53[1]; + uint32_t ttype2; + uint32_t reserved54[1]; + uint32_t ttype3; + uint32_t reserved55[1]; + uint32_t ttype4; + uint32_t reserved56[1]; + uint32_t ttype5; + uint32_t reserved57[1]; + uint32_t ttype6; + uint32_t reserved58[1]; + uint32_t ttype7; + uint32_t reserved59[1]; + uint32_t ttype8; + uint32_t reserved60[1]; + uint32_t ttype9; + uint32_t reserved61[1]; + uint32_t ttype10; + uint32_t reserved62[1]; + uint32_t ttype11; + uint32_t reserved63[1]; + uint32_t ttype12; + uint32_t reserved64[1]; + uint32_t ttype13; + uint32_t reserved65[1]; + uint32_t ttype14; + uint32_t reserved66[1]; + uint32_t ttype15; + uint32_t reserved67[1]; + uint32_t ttype16; + uint32_t reserved68[1]; + uint32_t ttype17; + uint32_t reserved69[1]; + uint32_t ttype18; + uint32_t reserved70[1]; + uint32_t ttype19; + uint32_t reserved71[1]; + uint32_t ttype20; + uint32_t reserved72[1]; + uint32_t ttype21; + uint32_t reserved73[3]; + uint32_t bwct0; + uint32_t bwct1; + uint32_t bwct2; + uint32_t bwct3; + uint32_t bwct4; + uint32_t bwst0; + uint32_t bwst1; + uint32_t reserved74[1]; + uint32_t ex_con; + uint32_t ex_st0; + uint32_t ex_st1; + uint32_t ex_st2; + uint32_t wp_adr; + uint32_t wp_adr_2nd; + uint32_t wp_ctrl; + uint32_t reserved75[1]; + uint32_t chker; + uint32_t chker_type; + uint32_t chker_adr; + uint32_t chker_adr_2nd; + uint32_t reserved76[40]; + uint32_t bwct0_2nd; + uint32_t reserved77[43]; + uint32_t ltct0_2nd; + uint32_t ltct1_2nd; + uint32_t ltct2_2nd; + uint32_t ltct3_2nd; + uint32_t reserved78[4]; + uint32_t bwct0_3rd; + uint32_t reserved79[3]; + uint32_t bwct0_4th; + uint32_t reserved80[11]; + uint32_t bwct0_5th; + uint32_t reserved81[19]; + uint32_t slva; +}; + +check_member(emi_regs, cona, 0x0000); +check_member(emi_regs, conb, 0x0008); +check_member(emi_regs, conc, 0x0010); +check_member(emi_regs, cond, 0x0018); +check_member(emi_regs, cone, 0x0020); +check_member(emi_regs, conf, 0x0028); +check_member(emi_regs, cong, 0x0030); +check_member(emi_regs, conh, 0x0038); +check_member(emi_regs, conh_2nd, 0x003c); +check_member(emi_regs, coni, 0x0040); +check_member(emi_regs, conj, 0x0048); +check_member(emi_regs, conm, 0x0060); +check_member(emi_regs, conn, 0x0068); +check_member(emi_regs, cono, 0x0070); +check_member(emi_regs, mdct, 0x0078); +check_member(emi_regs, mdct_2nd, 0x007c); +check_member(emi_regs, iocl, 0x00d0); +check_member(emi_regs, iocl_2nd, 0x00d4); +check_member(emi_regs, iocm, 0x00d8); +check_member(emi_regs, iocm_2nd, 0x00dc); +check_member(emi_regs, testb, 0x00e8); +check_member(emi_regs, testc, 0x00f0); +check_member(emi_regs, testd, 0x00f8); +check_member(emi_regs, arba, 0x0100); +check_member(emi_regs, arbb, 0x0108); +check_member(emi_regs, arbc, 0x0110); +check_member(emi_regs, arbd, 0x0118); +check_member(emi_regs, arbe, 0x0120); +check_member(emi_regs, arbf, 0x0128); +check_member(emi_regs, arbg, 0x0130); +check_member(emi_regs, arbh, 0x0138); +check_member(emi_regs, arbi, 0x0140); +check_member(emi_regs, arbi_2nd, 0x0144); +check_member(emi_regs, slct, 0x0158); + +struct chn_emi_regs { + uint32_t chn_cona; + uint32_t rsvd_1[1]; + uint32_t chn_conb; + uint32_t rsvd_2[1]; + uint32_t chn_conc; + uint32_t rsvd_3[1]; + uint32_t chn_mdct; + uint32_t rsvd_4[11]; + uint32_t chn_testb; + uint32_t rsvd_5[1]; + uint32_t chn_testc; + uint32_t rsvd_6[1]; + uint32_t chn_testd; + uint32_t rsvd_7[9]; + uint32_t chn_md_pre_mask; + uint32_t rsvd_8[1]; + uint32_t chn_md_pre_mask_shf; + uint32_t rsvd_9[45]; + uint32_t chn_arbi; + uint32_t chn_arbi_2nd; + uint32_t chn_arbj; + uint32_t chn_arbj_2nd; + uint32_t chn_arbk; + uint32_t chn_arbk_2nd; + uint32_t chn_slct; + uint32_t chn_arb_ref; + uint32_t rsvd_10[20]; + uint32_t chn_rkarb0; + uint32_t chn_rkarb1; + uint32_t chn_rkarb2; + uint32_t rsvd_11[144]; + uint32_t chn_eco3; + uint32_t rsvd_12[196]; + uint32_t chn_emi_shf0; + uint32_t chn_emi_regs_end; + +}; + +check_member(chn_emi_regs, chn_cona, 0x0000); +check_member(chn_emi_regs, chn_conb, 0x0008); +check_member(chn_emi_regs, chn_conc, 0x0010); +check_member(chn_emi_regs, chn_mdct, 0x0018); +check_member(chn_emi_regs, chn_testb, 0x0048); +check_member(chn_emi_regs, chn_testc, 0x0050); +check_member(chn_emi_regs, chn_testd, 0x0058); +check_member(chn_emi_regs, chn_md_pre_mask, 0x0080); +check_member(chn_emi_regs, chn_md_pre_mask_shf, 0x0088); +check_member(chn_emi_regs, chn_arbi, 0x0140); +check_member(chn_emi_regs, chn_arbi_2nd, 0x0144); +check_member(chn_emi_regs, chn_arbj, 0x0148); +check_member(chn_emi_regs, chn_arbj_2nd, 0x014c); +check_member(chn_emi_regs, chn_arbk, 0x0150); +check_member(chn_emi_regs, chn_arbk_2nd, 0x0154); +check_member(chn_emi_regs, chn_slct, 0x0158); +check_member(chn_emi_regs, chn_arb_ref, 0x015c); +check_member(chn_emi_regs, chn_rkarb0, 0x01b0); +check_member(chn_emi_regs, chn_rkarb1, 0x01b4); +check_member(chn_emi_regs, chn_rkarb2, 0x01b8); +check_member(chn_emi_regs, chn_eco3, 0x03fc); +check_member(chn_emi_regs, chn_emi_shf0, 0x0710); + +struct emi_mpu_regs { + uint32_t mpu_ctrl; + uint32_t mpu_dbg; + uint32_t rsvd_2[62]; + uint32_t mpu_sa0; + uint32_t rsvd_3[63]; + uint32_t mpu_ea0; + uint32_t rsvd_4[63]; + uint32_t mpu_apc0; + uint32_t rsvd_5[319]; + uint32_t mpu_ctrl_d0; + uint32_t rsvd_6[63]; + uint32_t rg_mask_d0; +}; + +check_member(emi_mpu_regs, mpu_dbg, 0x0004); +check_member(emi_mpu_regs, mpu_sa0, 0x0100); +check_member(emi_mpu_regs, mpu_ea0, 0x0200); +check_member(emi_mpu_regs, mpu_apc0, 0x0300); +check_member(emi_mpu_regs, mpu_ctrl_d0, 0x0800); +check_member(emi_mpu_regs, rg_mask_d0, 0x0900); + +enum { + TESTCHIP_DMA1_DMA_LP4MATAB_OPT_SHIFT = 12, +}; + +enum { + MISC_STATUSA_REFRESH_QUEUE_CNT_SHIFT = 24, + MISC_STATUSA_REFRESH_QUEUE_CNT_MASK = 0x0f000000, +}; + +enum { + SPCMDRESP_RDDQC_RESPONSE_SHIFT = 7, + SPCMDRESP_ZQLAT_RESPONSE_SHIFT = 6, + SPCMDRESP_ZQC_RESPONSE_SHIFT = 4, +}; + +enum { + TESTRPT_DM_CMP_CPT_RK0_SHIFT = 0, +}; + +enum { + DDRCONF0_DM4TO1MODE_SHIFT = 22, + DDRCONF0_RDATRST_SHIFT = 0, +}; + +enum { + DRAMCTRL_ADRDECEN_TARKMODE_SHIFT = 1, +}; + +enum { + PERFCTL0_RWOFOEN_SHIFT = 4, +}; + +enum { + RSTMASK_RSV_DRAM_SUPPORT_RANK_NUM_SHIFT = 12, +}; + +enum { + PADCTRL_DQIENLATEBEGIN_SHIFT = 3, + PADCTRL_DQIENQKEND_SHIFT = 0, + PADCTRL_DQIENQKEND_MASK = 0x00000003, +}; + +enum { + RKCFG_RKSWAP_SHIFT = 7, + RKCFG_RKMODE_SHIFT = 4, + RKCFG_RKMODE_MASK = 0x00000070, + RKCFG_TXRANKFIX_SHIFT = 3, + RKCFG_TXRANK_SHIFT = 0, + RKCFG_TXRANK_MASK = 0x00000003, +}; +enum { + REFCTRL0_REFDIS_SHIFT = 29, + REFCTRL0_PBREFEN_SHIFT = 18, +}; + +enum { + MRS_MPCRK_SHIFT = 28, + MRS_MPCRK_MASK = 0x30000000, + MRS_MRSRK_SHIFT = 24, + MRS_MRSRK_MASK = 0x03000000, + MRS_MRSMA_SHIFT = 8, + MRS_MRSMA_MASK = 0x001fff00, + MRS_MRSOP_SHIFT = 0, + MRS_MRSOP_MASK = 0x000000ff, +}; + +enum { + SPCMD_DQSGCNTRST_SHIFT = 9, + SPCMD_DQSGCNTEN_SHIFT = 8, + SPCMD_RDDQCEN_SHIFT = 7, + SPCMD_ZQLATEN_SHIFT = 6, + SPCMD_ZQCEN_SHIFT = 4, + SPCMD_MRWEN_SHIFT = 0, +}; + +enum { + SPCMDCTRL_RDDQCDIS_SHIFT = 11, +}; + +enum { + MPC_OPTION_MPCRKEN_SHIFT = 17, +}; + +enum { + TEST2_0_PAT0_SHIFT = 8, + TEST2_0_PAT0_MASK = 0x0000ff00, + TEST2_0_PAT1_SHIFT = 0, + TEST2_0_PAT1_MASK = 0x000000ff, +}; + +enum { + TEST2_3_TEST2W_SHIFT = 31, + TEST2_3_TEST2R_SHIFT = 30, + TEST2_3_TEST1_SHIFT = 29, + TEST2_3_TESTAUDPAT_SHIFT = 7, + TEST2_3_TESTCNT_SHIFT = 0, + TEST2_3_TESTCNT_MASK = 0x0000000f, +}; + +enum { + TEST2_4_TESTAGENTRKSEL_MASK = 0x70000000, + TEST2_4_TESTAGENTRK_SHIFT = 24, + TEST2_4_TESTAGENTRK_MASK = 0x03000000, + TEST2_4_TEST_REQ_LEN1_SHIFT = 17, + TEST2_4_TESTXTALKPAT_SHIFT = 16, + TEST2_4_TESTAUDMODE_SHIFT = 15, + TEST2_4_TESTAUDBITINV_SHIFT = 14, + TEST2_4_TESTAUDINIT_SHIFT = 8, + TEST2_4_TESTAUDINIT_MASK = 0x00001f00, + TEST2_4_TESTSSOXTALKPAT_SHIFT = 7, + TEST2_4_TESTSSOPAT_SHIFT = 6, + TEST2_4_TESTAUDINC_SHIFT = 0, + TEST2_4_TESTAUDINC_MASK = 0x0000001f, +}; + +enum { + MR_GOLDEN_MR15_GOLDEN_MASK = 0x0000ff00, + MR_GOLDEN_MR20_GOLDEN_MASK = 0x000000ff, +}; + +enum { + DQSOSCR_AR_COARSE_TUNE_DQ_SW_SHIFT = 7, +}; + +enum { + DUMMY_RD_DQSG_DMYWR_EN_SHIFT = 23, + DUMMY_RD_DQSG_DMYRD_EN_SHIFT = 22, + DUMMY_RD_SREF_DMYRD_EN_SHIFT = 21, + DUMMY_RD_DUMMY_RD_EN_SHIFT = 20, + DUMMY_RD_DMY_RD_DBG_SHIFT = 7, + DUMMY_RD_DMY_WR_DBG_SHIFT = 6, +}; + +enum { + SHUCTRL2_R_DVFS_OPTION_SHIFT = 15, + SHUCTRL2_R_DVFS_PARK_N_SHIFT = 14, +}; + +enum { + STBCAL_DQSIENMODE_SELPH_SHIFT = 30, + STBCAL_STBCALEN_SHIFT = 24, + STBCAL_STB_SELPHYCALEN_SHIFT = 22, +}; + +enum { + STBCAL1_STBCNT_LATCH_EN_SHIFT = 11, + STBCAL1_STBENCMPEN_SHIFT = 10, + STBCAL1_DQSIEN_7_COARSE_TUNE_EN_SHIFT = 5, +}; + +enum { + SHU_ACTIM_XRT_XRTR2R_SHIFT = 0, + SHU_ACTIM_XRT_XRTR2R_MASK = 0x0000000f, +}; + +enum { + SHU_CONF1_DATLAT_DSEL_PHY_SHIFT = 26, + SHU_CONF1_DATLAT_DSEL_PHY_MASK = 0x7c000000, + SHU_CONF1_DATLAT_DSEL_SHIFT = 8, + SHU_CONF1_DATLAT_DSEL_MASK = 0x00001f00, + SHU_CONF1_DATLAT_SHIFT = 0, + SHU_CONF1_DATLAT_MASK = 0x0000001f, +}; + +enum { + SHU_RANKCTL_RANKINCTL_PHY_SHIFT = 28, + SHU_RANKCTL_RANKINCTL_PHY_MASK = 0xf0000000, + SHU_RANKCTL_RANKINCTL_ROOT1_SHIFT = 24, + SHU_RANKCTL_RANKINCTL_ROOT1_MASK = 0x0f000000, + SHU_RANKCTL_RANKINCTL_SHIFT = 20, + SHU_RANKCTL_RANKINCTL_MASK = 0x00f00000, +}; + +enum { + SHU_ODTCTRL_RODT_SHIFT = 4, + SHU_ODTCTRL_RODT_MASK = 0x000000f0, +}; + +enum { + SHU1_WODT_DBIWR_SHIFT = 29, +}; + +enum { + SHURK_DQSCTL_DQSINCTL_SHIFT = 0, + SHURK_DQSCTL_DQSINCTL_MASK = 0x0000000f, +}; + +enum { + SHURK_SELPH_ODTEN0_TXDLY_B1_RODTEN_P1_SHIFT = 12, + SHURK_SELPH_ODTEN0_TXDLY_B1_RODTEN_SHIFT = 8, + SHURK_SELPH_ODTEN0_TXDLY_B0_RODTEN_P1_SHIFT = 4, + SHURK_SELPH_ODTEN0_TXDLY_B0_RODTEN_SHIFT = 0, +}; + +enum { + SHURK_SELPH_ODTEN1_DLY_B1_RODTEN_P1_SHIFT = 12, + SHURK_SELPH_ODTEN1_DLY_B1_RODTEN_SHIFT = 8, + SHURK_SELPH_ODTEN1_DLY_B0_RODTEN_P1_SHIFT = 4, + SHURK_SELPH_ODTEN1_DLY_B0_RODTEN_SHIFT = 0, +}; + +enum { + SHURK_SELPH_DQSG0_TX_DLY_DQS1_GATED_P1_SHIFT = 12, + SHURK_SELPH_DQSG0_TX_DLY_DQS1_GATED_SHIFT = 8, + SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_SHIFT = 4, + SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_P1_MASK = 0x00000070, + SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_SHIFT = 0, + SHURK_SELPH_DQSG0_TX_DLY_DQS0_GATED_MASK = 0x00000007, +}; + +enum { + SHURK_SELPH_DQSG1_REG_DLY_DQS1_GATED_P1_SHIFT = 12, + SHURK_SELPH_DQSG1_REG_DLY_DQS1_GATED_SHIFT = 8, + SHURK_SELPH_DQSG1_REG_DLY_DQS0_GATED_P1_SHIFT = 4, + SHURK_SELPH_DQSG1_REG_DLY_DQS0_GATED_SHIFT = 0, +}; + +enum { + B0_DQ5_RG_RX_ARDQ_VREF_EN_B0_SHIFT = 16, +}; + +enum { + B0_DQ6_RG_RX_ARDQ_BIAS_VREF_SEL_B0_SHIFT = 14, + B0_DQ6_RG_RX_ARDQ_BIAS_VREF_SEL_B0_MASK = 0x0000c000, + B0_DQ6_RG_RX_ARDQ_RPRE_TOG_EN_B0_SHIFT = 5, +}; + +enum { + B1_DQ5_RG_RX_ARDQ_VREF_EN_B1_SHIFT = 16, +}; + +enum { + B1_DQ6_RG_RX_ARDQ_BIAS_VREF_SEL_B1_SHIFT = 14, + B1_DQ6_RG_RX_ARDQ_BIAS_VREF_SEL_B1_MASK = 0x0000c000, + B1_DQ6_RG_RX_ARDQ_RPRE_TOG_EN_B1_SHIFT = 5, +}; + +enum { + MISC_CTRL1_R_DMSTBENCMP_RK_OPT_SHIFT = 25, + MISC_CTRL1_R_DMAR_FINE_TUNE_DQ_SW_SHIFT = 7, + MISC_CTRL1_R_DMPHYRST_SHIFT = 1, +}; + +enum { + MISC_STBERR_RK_R_STBERR_RK_R_MASK = 0x0000ffff, +}; + +enum { + MISC_STBERR_RK_F_STBERR_RK_F_MASK = 0x0000ffff, +}; + +enum { + SHU1_B0_DQ5_RG_RX_ARDQ_VREF_SEL_B0_SHIFT = 0, + SHU1_B0_DQ5_RG_RX_ARDQ_VREF_SEL_B0_MASK = 0x0000003f, +}; + +enum { + SHU1_B0_DQ7_R_DMDQMDBI_SHU_B0_SHIFT = 7, + SHU1_B0_DQ7_R_DMRANKRXDVS_B0_SHIFT = 0, + SHU1_B0_DQ7_R_DMRANKRXDVS_B0_MASK = 0x0000000f, +}; + +enum { + SHU1_B1_DQ5_RG_RX_ARDQ_VREF_SEL_B1_SHIFT = 0, + SHU1_B1_DQ5_RG_RX_ARDQ_VREF_SEL_B1_MASK = 0x0000003f, +}; + +enum { + SHU1_B1_DQ7_R_DMDQMDBI_SHU_B1_SHIFT = 7, + SHU1_B1_DQ7_R_DMRANKRXDVS_B1_SHIFT = 0, + SHU1_B1_DQ7_R_DMRANKRXDVS_B1_MASK = 0x0000000f, +}; + +enum { + SHU1_CA_CMD0_RG_TX_ARCLK_DRVN_PRE_SHIFT = 12, + SHU1_CA_CMD0_RG_TX_ARCLK_DRVN_PRE_MASK = 0x00007000, +}; + +enum { + SHU1_CA_CMD3_RG_TX_ARCMD_PU_PRE_SHIFT = 10, + SHU1_CA_CMD3_RG_TX_ARCMD_PU_PRE_MASK = 0x00000c00, +}; + +enum { + SHU1_B0_DQ6_RK_RX_ARDQS0_F_DLY_B0_MASK = 0x7f000000, + SHU1_B0_DQ6_RK_RX_ARDQS0_R_DLY_B0_MASK = 0x007f0000, + SHU1_B0_DQ6_RK_RX_ARDQM0_F_DLY_B0_MASK = 0x00003f00, + SHU1_B0_DQ6_RK_RX_ARDQM0_R_DLY_B0_MASK = 0x0000003f, +}; + +enum { + SHU1_B0_DQ7_RK_ARFINE_TUNE_PBYTE_B0_SHIFT = 24, + SHU1_B0_DQ7_RK_ARFINE_TUNE_PBYTE_B0_MASK = 0x3f000000, + SHU1_B0_DQ7_RK_ARFINE_TUNE_DQM_B0_SHIFT = 16, + SHU1_B0_DQ7_RK_ARFINE_TUNE_DQM_B0_MASK = 0x003f0000, + SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_SHIFT = 8, + SHU1_B0_DQ7_RK_ARFINE_TUNE_DQ_B0_MASK = 0x00003f00, +}; + +enum { + SHU1_B1_DQ7_RK_ARFINE_TUNE_PBYTE_B1_SHIFT = 24, + SHU1_B1_DQ7_RK_ARFINE_TUNE_PBYTE_B1_MASK = 0x3f000000, + SHU1_B1_DQ7_RK_ARFINE_TUNE_DQM_B1_SHIFT = 16, + SHU1_B1_DQ7_RK_ARFINE_TUNE_DQM_B1_MASK = 0x003f0000, + SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_SHIFT = 8, + SHU1_B1_DQ7_RK_ARFINE_TUNE_DQ_B1_MASK = 0x00003f00, +}; + +enum { + SHU1_CA_CMD9_RG_RK_ARFINE_TUNE_CLK_SHIFT = 24, + SHU1_CA_CMD9_RG_RK_ARFINE_TUNE_CLK_MASK = 0x3f000000, + SHU1_CA_CMD9_RG_RK_ARFINE_TUNE_CS_MASK = 0x0000003f, +}; + +enum { + SHU1_R2_B1_DQ1_RK2_TX_ARDQS0_DLY_B1_SHIFT = 24, + SHU1_R2_B1_DQ1_RK2_TX_ARDQS0_DLY_B1_MASK = 0x0f000000, + SHU1_R2_B1_DQ1_RK2_TX_ARDQM0_DLY_B1_SHIFT = 0, + SHU1_R2_B1_DQ1_RK2_TX_ARDQM0_DLY_B1_MASK = 0x0000000f, +}; + +enum { + SHU1_R2_B1_DQ7_RK2_ARFINE_TUNE_PBYTE_B1_SHIFT = 24, + SHU1_R2_B1_DQ7_RK2_ARFINE_TUNE_PBYTE_B1_MASK = 0x3f000000, + SHU1_R2_B1_DQ7_RK2_ARFINE_TUNE_DQM_B1_SHIFT = 16, + SHU1_R2_B1_DQ7_RK2_ARFINE_TUNE_DQM_B1_MASK = 0x003f0000, + SHU1_R2_B1_DQ7_RK2_ARFINE_TUNE_DQ_B1_SHIFT = 8, + SHU1_R2_B1_DQ7_RK2_ARFINE_TUNE_DQ_B1_MASK = 0x00003f00, +}; + +struct dramc_channel_regs { + union { + struct dramc_ddrphy_ao_regs phy; + uint8_t size_ddrphy_ao_regs[0x2000]; + }; + + union { + struct dramc_ao_regs ao; + uint8_t size_ao_regs[0x2000]; + }; + + union { + struct dramc_nao_regs nao; + uint8_t size_nao_regs[0x1000]; + }; + + union { + struct chn_emi_regs emi; + uint8_t size_emi_regs[0x1000]; + }; + + union { + struct dramc_ddrphy_nao_regs phy_nao; + uint8_t size_ddrphy_nao_regs[0x2000]; + }; +}; + +static struct dramc_channel_regs *const ch = (void *)DRAMC_CH_BASE; +static struct emi_mpu_regs *const emi_mpu = (void *)EMI_MPU_BASE; + +#endif /* _DRAMC_REGISTER_H_ */ diff --git a/src/soc/mediatek/mt8183/include/soc/emi.h b/src/soc/mediatek/mt8183/include/soc/emi.h index edc27a8..5969450 100644 --- a/src/soc/mediatek/mt8183/include/soc/emi.h +++ b/src/soc/mediatek/mt8183/include/soc/emi.h @@ -1,7 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright 2018 MediaTek Inc. + * Copyright 2017 MediaTek Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,7 +18,26 @@
#include <stdint.h> #include <types.h> +#include <soc/dramc_common_mt8183.h>
+struct sdram_params { + u32 impedance[2][4]; + u8 wr_level[CHANNEL_NUM][RANK_MAX][DQS_NUMBER]; + u8 cbt_cs[CHANNEL_NUM][RANK_MAX]; + u8 cbt_mr12[CHANNEL_NUM][RANK_MAX]; + s8 clk_delay; + s8 dqs_delay[CHANNEL_NUM]; + u32 EMI_CONA_VAL; + u32 EMI_CONH_VAL; + u32 EMI_CONF_VAL; + u32 CHN_EMI_CONA_VAL[CHANNEL_NUM]; + u32 cbt_mode_extern; +}; + +int complex_mem_test(u8 *start, unsigned int len); size_t sdram_size(void); +const struct sdram_params *get_sdram_config(void); +void mt_set_emi(const struct sdram_params *params); +void mt_mem_init(const struct sdram_params *params);
-#endif +#endif /* SOC_MEDIATEK_MT8183_EMI_H */ diff --git a/src/soc/mediatek/mt8183/include/soc/memlayout.ld b/src/soc/mediatek/mt8183/include/soc/memlayout.ld index f148eed..2a6d42d 100644 --- a/src/soc/mediatek/mt8183/include/soc/memlayout.ld +++ b/src/soc/mediatek/mt8183/include/soc/memlayout.ld @@ -39,7 +39,7 @@ SRAM_END(0x00120000)
SRAM_L2C_START(0x00200000) - OVERLAP_DECOMPRESSOR_ROMSTAGE(0x000201000, 92K) + OVERLAP_DECOMPRESSOR_ROMSTAGE(0x000201000, 110K) BOOTBLOCK(0x00227000, 89K) VERSTAGE(0x0023E000, 114K) SRAM_L2C_END(0x00280000) diff --git a/src/soc/mediatek/mt8183/memory.c b/src/soc/mediatek/mt8183/memory.c new file mode 100644 index 0000000..7fee8b8 --- /dev/null +++ b/src/soc/mediatek/mt8183/memory.c @@ -0,0 +1,51 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <assert.h> +#include <console/console.h> +#include <soc/dramc_pi_api.h> +#include <soc/emi.h> +#include <symbols.h> + +void mt_mem_init(const struct sdram_params *params) +{ + u64 rank_size[RANK_MAX]; + + /* memory calibration */ + mt_set_emi(params); + + if (IS_ENABLED(CONFIG_MEMORY_TEST)) { + size_t r; + u8 *addr = _dram; + + get_dram_rank_size(&rank_size[0]); + + for (r = RANK_0; r < RANK_MAX; r++) { + int i; + + if (rank_size[r] == 0) + break; + + i = complex_mem_test(addr, 0x2000); + + printk(BIOS_DEBUG, "[MEM] complex R/W mem test %s : %d\n", + (i == 0) ? "pass" : "fail", i); + + ASSERT(i == 0); + + addr += rank_size[r]; + } + } +} diff --git a/src/soc/mediatek/mt8183/pll.c b/src/soc/mediatek/mt8183/pll.c index e0dd388..b099e99 100644 --- a/src/soc/mediatek/mt8183/pll.c +++ b/src/soc/mediatek/mt8183/pll.c @@ -280,6 +280,35 @@ setbits_le32(pll->div_reg, PLL_PCW_CHG); }
+static void mem_pll_init(void) +{ + unsigned int tmp; + + /* CLKSQ Enable */ + setbits_le32(&mtk_apmixed->ap_pll_con0, 0x85); + udelay(100); + + /* CLKSQ LPF Enable */ + setbits_le32(&mtk_apmixed->ap_pll_con0, 0x87); + udelay(1); + + /* power on MPLL */ + setbits_le32(&mtk_apmixed->mpll_pwr_con0, 0x3); + udelay(1); + + /* turn off ISO of MPLL */ + setbits_le32(&mtk_apmixed->mpll_pwr_con0, 0x1); + udelay(1); + tmp = read32(&mtk_apmixed->mpll_con1); + + /* Config MPLL freq */ + setbits_le32(&mtk_apmixed->mpll_con1, tmp | 0x80000000); + + /* enable MPLL */ + setbits_le32(&mtk_apmixed->mpll_con0, 0x181); + udelay(20); +} + void mt_pll_init(void) { int i; @@ -348,4 +377,6 @@
/* enable [14] dramc_pll104m_ck */ setbits_le32(&mtk_topckgen->clk_misc_cfg_0, 1 << 14); + + mem_pll_init(); }