143 lines
4.7 KiB
C
143 lines
4.7 KiB
C
|
/*
|
||
|
* 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);
|
||
|
}
|