aboutsummaryrefslogtreecommitdiff
path: root/src/soc/mediatek/mt8173/emi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/mediatek/mt8173/emi.c')
-rw-r--r--src/soc/mediatek/mt8173/emi.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/soc/mediatek/mt8173/emi.c b/src/soc/mediatek/mt8173/emi.c
new file mode 100644
index 0000000000..f6ef40f8f3
--- /dev/null
+++ b/src/soc/mediatek/mt8173/emi.c
@@ -0,0 +1,142 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2015 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 <assert.h>
+#include <boardid.h>
+#include <console/console.h>
+#include <delay.h>
+#include <string.h>
+#include <soc/addressmap.h>
+#include <soc/dramc_common.h>
+#include <soc/dramc_register.h>
+#include <soc/dramc_pi_api.h>
+#include <soc/mt6391.h>
+#include <soc/pll.h>
+
+struct emi_regs *emi_regs = (void *)EMI_BASE;
+
+static void dram_vcore_adjust(void)
+{
+ /* options: Vcore_HV_LPPDR3/Vcore_NV_LPPDR3/Vcore_LV_LPPDR3 */
+ mt6391_write(PMIC_RG_VCORE_CON9, Vcore_NV_LPPDR3, 0x7F, 0);
+ mt6391_write(PMIC_RG_VCORE_CON10, Vcore_NV_LPPDR3, 0x7F, 0);
+}
+
+static void dram_vmem_adjust(void)
+{
+ /* options: Vmem_HV_LPPDR3/Vmem_NV_LPPDR3/Vmem_LV_LPPDR3 */
+ mt6391_write(PMIC_RG_VDRM_CON9, Vmem_NV_LPDDR3, 0x7F, 0);
+ mt6391_write(PMIC_RG_VDRM_CON10, Vmem_NV_LPDDR3, 0x7F, 0);
+}
+
+static void emi_init(const struct mt8173_sdram_params *sdram_params)
+{
+ /* EMI setting initialization */
+ write32(&emi_regs->emi_conf, sdram_params->emi_set.conf);
+ write32(&emi_regs->emi_conm, sdram_params->emi_set.conm_1);
+ write32(&emi_regs->emi_arbi, sdram_params->emi_set.arbi);
+ write32(&emi_regs->emi_arba, sdram_params->emi_set.arba);
+ write32(&emi_regs->emi_arbc, sdram_params->emi_set.arbc);
+ write32(&emi_regs->emi_arbd, sdram_params->emi_set.arbd);
+ write32(&emi_regs->emi_arbe, sdram_params->emi_set.arbe);
+ write32(&emi_regs->emi_arbf, sdram_params->emi_set.arbf);
+ write32(&emi_regs->emi_arbg, sdram_params->emi_set.arbg);
+ write32(&emi_regs->emi_arbj, sdram_params->emi_set.arbj);
+ write32(&emi_regs->emi_cona, sdram_params->emi_set.cona);
+ write32(&emi_regs->emi_testd, sdram_params->emi_set.testd);
+ write32(&emi_regs->emi_bmen, sdram_params->emi_set.bmen);
+ write32(&emi_regs->emi_conb, sdram_params->emi_set.conb);
+ write32(&emi_regs->emi_conc, sdram_params->emi_set.conc);
+ write32(&emi_regs->emi_cond, sdram_params->emi_set.cond);
+ write32(&emi_regs->emi_cone, sdram_params->emi_set.cone);
+ write32(&emi_regs->emi_cong, sdram_params->emi_set.cong);
+ write32(&emi_regs->emi_conh, sdram_params->emi_set.conh);
+ write32(&emi_regs->emi_slct, sdram_params->emi_set.slct_1);
+ write32(&emi_regs->emi_mdct, sdram_params->emi_set.mdct_1);
+ write32(&emi_regs->emi_arbk, sdram_params->emi_set.arbk);
+ write32(&emi_regs->emi_testc, sdram_params->emi_set.testc);
+ write32(&emi_regs->emi_mdct, sdram_params->emi_set.mdct_2);
+ write32(&emi_regs->emi_testb, sdram_params->emi_set.testb);
+ write32(&emi_regs->emi_slct, sdram_params->emi_set.slct_2);
+ write32(&emi_regs->emi_conm, sdram_params->emi_set.conm_2);
+ write32(&emi_regs->emi_test0, sdram_params->emi_set.test0);
+ write32(&emi_regs->emi_test1, sdram_params->emi_set.test1);
+}
+
+static void do_calib(const struct mt8173_sdram_params *sdram_params)
+{
+ u32 channel;
+
+ sw_impedance_cal(CHANNEL_A, sdram_params);
+ sw_impedance_cal(CHANNEL_B, sdram_params);
+
+ /* SPM_CONTROL_AFTERK */
+ transfer_to_reg_control();
+
+ /* do dram calibration for channel A and B */
+ for(channel = 0; channel < CHANNEL_NUM; channel++) {
+ ca_training(channel, sdram_params);
+ write_leveling(channel, sdram_params);
+
+ /* rx gating and datlat for single or dual rank */
+ if (is_dual_rank(channel, sdram_params)) {
+ dual_rank_rx_dqs_gating_cal(channel, sdram_params);
+ dual_rank_rx_datlat_cal(channel, sdram_params);
+ } else {
+ rx_dqs_gating_cal(channel, 0, sdram_params);
+ rx_datlat_cal(channel, 0, sdram_params);
+ }
+
+ clk_duty_cal(channel);
+ /* rx window perbit calibration */
+ perbit_window_cal(channel, RX_WIN);
+ /* tx window perbit calibration */
+ perbit_window_cal(channel, TX_WIN);
+
+ dramc_rankinctl_config(channel, sdram_params);
+ dramc_runtime_config(channel, sdram_params);
+ }
+
+ /* SPM_CONTROL_AFTERK */
+ transfer_to_spm_control();
+}
+
+static void init_dram(const struct mt8173_sdram_params *sdram_params)
+{
+ emi_init(sdram_params);
+
+ dramc_pre_init(CHANNEL_A, sdram_params);
+ dramc_pre_init(CHANNEL_B, sdram_params);
+
+ div2_phase_sync();
+
+ dramc_init(CHANNEL_A, sdram_params);
+ dramc_init(CHANNEL_B, sdram_params);
+}
+
+void mt_set_emi(const struct mt8173_sdram_params *sdram_params)
+{
+ /* voltage info */
+ dram_vcore_adjust();
+ dram_vmem_adjust();
+
+ if (sdram_params->type != TYPE_LPDDR3) {
+ die("The DRAM type is not supported");
+ }
+
+ init_dram(sdram_params);
+ do_calib(sdram_params);
+}