| /* |
| * 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> |
| #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 */ |
| 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); |
| } |
| |
| 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) { |
| setbits_le32(&mt8173_pericfg->axi_bus_ctl3, PERISYS_4G_SUPPORT); |
| setbits_le32(&mt8173_infracfg->infra_misc, DDR_4GB_SUPPORT_EN); |
| } else { |
| clrbits_le32(&mt8173_pericfg->axi_bus_ctl3, PERISYS_4G_SUPPORT); |
| clrbits_le32(&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(); |
| } |