blob: f3ea7614e45137ed359d98048fdbb1289f3d57d8 [file] [log] [blame]
/*
* 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 <device/mmio.h>
#include <boardid.h>
#include <console/console.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/pmic_wrap.h>
#include <soc/pll.h>
#include <soc/infracfg.h>
#include <soc/pericfg.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 */
pwrap_write_field(PMIC_RG_VCORE_CON9, Vcore_NV_LPPDR3, 0x7F, 0);
pwrap_write_field(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 */
pwrap_write_field(PMIC_RG_VDRM_CON9, Vmem_NV_LPDDR3, 0x7F, 0);
pwrap_write_field(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);
}
size_t sdram_size(void)
{
u32 value = read32(&emi_regs->emi_cona);
u32 bit_counter = 0;
/* check if dual channel */
if (value & CONA_DUAL_CH_EN)
bit_counter++;
/* check if 32bit, 32 = 2^5*/
if (value & CONA_32BIT_EN)
bit_counter += 5;
else
bit_counter += 4;
/* check column address */
/* 00 is 9 bits, 01 is 10 bits, 10 is 11 bits */
bit_counter += ((value & COL_ADDR_BITS_MASK) >> COL_ADDR_BITS_SHIFT) +
9;
/* check if row address */
/*00 is 13 bits, 01 is 14 bits, 10 is 15bits, 11 is 16 bits */
bit_counter += ((value & ROW_ADDR_BITS_MASK) >> ROW_ADDR_BITS_SHIFT) +
13;
/* check if dual rank */
if (value & CONA_DUAL_RANK_EN)
bit_counter++;
/* add bank address bit, LPDDR3 is 8 banks =2^3 */
bit_counter += 3;
/*transfor bits to bytes */
return ((size_t)1 << (bit_counter - 3));
}
static void init_4GB_mode(void)
{
if (sdram_size() == (size_t)4 * GiB) {
setbits32(&mt8173_pericfg->axi_bus_ctl3, PERISYS_4G_SUPPORT);
setbits32(&mt8173_infracfg->infra_misc, DDR_4GB_SUPPORT_EN);
} else {
clrbits32(&mt8173_pericfg->axi_bus_ctl3, PERISYS_4G_SUPPORT);
clrbits32(&mt8173_infracfg->infra_misc, DDR_4GB_SUPPORT_EN);
}
}
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);
init_4GB_mode();
}