diff options
Diffstat (limited to 'src/soc/mediatek/mt8173/emi.c')
-rw-r--r-- | src/soc/mediatek/mt8173/emi.c | 142 |
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); +} |