/* * 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 #include #include #include #include #include #include #include #include #include #include #include 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); }