mediatek/mt8173: Add EMI driver, DRAM initialization
BUG=none TEST=emerge-oak coreboot BRANCH=none Change-Id: I6b05898de2d0022e0de7b18f1db3c3e9c06d8135 Signed-off-by: Patrick Georgi <pgeorgi@chromium.org> Original-Commit-Id: b614eeb1bba5660438c214e82225832809caca8e Original-Change-Id: I0f7b0a426dae1548b34114a024c92befdf6002f6 Original-Signed-off-by: Peter Kao <peter.kao@mediatek.com> Original-Reviewed-on: https://chromium-review.googlesource.com/292692 Original-Commit-Ready: Yidi Lin <yidi.lin@mediatek.com> Original-Tested-by: Yidi Lin <yidi.lin@mediatek.com> Original-Reviewed-by: Julius Werner <jwerner@chromium.org> Reviewed-on: https://review.coreboot.org/13105 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
parent
b74a2eca80
commit
da1e02a3a0
|
@ -17,6 +17,10 @@ config SOC_MEDIATEK_MT8173
|
||||||
|
|
||||||
if SOC_MEDIATEK_MT8173
|
if SOC_MEDIATEK_MT8173
|
||||||
|
|
||||||
|
config MEMORY_TEST
|
||||||
|
bool
|
||||||
|
default n
|
||||||
|
|
||||||
config DEBUG_SOC_DRIVER
|
config DEBUG_SOC_DRIVER
|
||||||
bool "The top level switch for soc driver debug message"
|
bool "The top level switch for soc driver debug message"
|
||||||
default n
|
default n
|
||||||
|
|
|
@ -43,6 +43,7 @@ verstage-$(CONFIG_SPI_FLASH) += flash_controller.c
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
romstage-$(CONFIG_SPI_FLASH) += flash_controller.c
|
romstage-$(CONFIG_SPI_FLASH) += flash_controller.c
|
||||||
|
romstage-y += pll.c
|
||||||
romstage-y += timer.c
|
romstage-y += timer.c
|
||||||
|
|
||||||
romstage-$(CONFIG_DRIVERS_UART) += uart.c
|
romstage-$(CONFIG_DRIVERS_UART) += uart.c
|
||||||
|
@ -50,6 +51,8 @@ romstage-y += cbmem.c
|
||||||
romstage-y += spi.c
|
romstage-y += spi.c
|
||||||
romstage-y += gpio.c
|
romstage-y += gpio.c
|
||||||
romstage-y += pmic_wrap.c mt6391.c
|
romstage-y += pmic_wrap.c mt6391.c
|
||||||
|
romstage-y += memory.c
|
||||||
|
romstage-y += emi.c dramc_pi_basic_api.c dramc_pi_calibration_api.c
|
||||||
romstage-y += mmu_operations.c
|
romstage-y += mmu_operations.c
|
||||||
romstage-y += rtc.c
|
romstage-y += rtc.c
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,879 @@
|
||||||
|
/*
|
||||||
|
* 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/barrier.h>
|
||||||
|
#include <arch/io.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <console/console.h>
|
||||||
|
#include <delay.h>
|
||||||
|
#include <soc/addressmap.h>
|
||||||
|
#include <soc/dramc_common.h>
|
||||||
|
#include <soc/dramc_register.h>
|
||||||
|
#include <soc/dramc_pi_api.h>
|
||||||
|
#include <soc/emi.h>
|
||||||
|
#include <soc/mt6391.h>
|
||||||
|
#include <soc/pll.h>
|
||||||
|
#include <soc/spm.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
struct mem_pll {
|
||||||
|
u8 delay;
|
||||||
|
u8 phase;
|
||||||
|
u8 done;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline u8 is_dual_rank(u32 channel,
|
||||||
|
const struct mt8173_sdram_params *sdram_params)
|
||||||
|
{
|
||||||
|
/* judge ranks from EMI_CONA[17] (cha) and EMI_CONA[16] (chb) */
|
||||||
|
return (sdram_params->emi_set.cona & (1 << (17 - channel))) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mem_pll_pre_init(u32 channel)
|
||||||
|
{
|
||||||
|
write32(&ch[channel].ddrphy_regs->lpddr2_3, 0x1 << 29 | 0x1 << 25 |
|
||||||
|
0xf << 16 | 0xffff);
|
||||||
|
|
||||||
|
write32(&ch[channel].ddrphy_regs->lpddr2_4, 0x1 << 29 | 0x1 << 25 |
|
||||||
|
0xf << 16 | 0xffff);
|
||||||
|
|
||||||
|
/* adjust DQS/DQM phase to get best margin */
|
||||||
|
write32(&ch[channel].ddrphy_regs->selph12, 0x1 << 28 | 0xf << 20 |
|
||||||
|
0x1 << 12 | 0xf << 4);
|
||||||
|
/* adjust DQ phase to get best margin */
|
||||||
|
write32(&ch[channel].ddrphy_regs->selph13, 0xffffffff << 0);
|
||||||
|
write32(&ch[channel].ddrphy_regs->selph14, 0xffffffff << 0);
|
||||||
|
|
||||||
|
/* fix OCV effect */
|
||||||
|
write32(&ch[channel].ddrphy_regs->selph15, 0x1 << 4 | 0xf << 0);
|
||||||
|
|
||||||
|
/* pll register control by CPU and select internal pipe path */
|
||||||
|
write32(&ch[channel].ddrphy_regs->peri[2], 0x11 << 24 | 0x11 << 16 |
|
||||||
|
0xff << 8 | 0x11 << 0);
|
||||||
|
write32(&ch[channel].ddrphy_regs->peri[3], 0x11 << 24 | 0x51 << 16 |
|
||||||
|
0x11 << 8 | 0x11 << 0);
|
||||||
|
|
||||||
|
/* enable clock sync and spm control clock */
|
||||||
|
write32(&ch[channel].ddrphy_regs->mempll_divider, 0x9 << 24 |
|
||||||
|
0x1 << 15 |
|
||||||
|
0x2 << 4 |
|
||||||
|
0x1 << 1 |
|
||||||
|
0x1 << 0);
|
||||||
|
/* pll2 enable from CPU control */
|
||||||
|
write32(&ch[channel].ddrphy_regs->mempll05_divider, 0x1 << 27);
|
||||||
|
|
||||||
|
/* enable chip top memory clock */
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->mempll_divider, 0x1 << 4);
|
||||||
|
|
||||||
|
/* disable C/A and DQ M_CK clock gating */
|
||||||
|
clrbits_le32(&ch[channel].ddrphy_regs->ddrphy_cg_ctrl, 0x1 << 2 |
|
||||||
|
0x1 << 1);
|
||||||
|
|
||||||
|
/* enable spm control clock */
|
||||||
|
clrbits_le32(&ch[channel].ddrphy_regs->mempll_divider, 0x1 << 15 |
|
||||||
|
0x1 << 0);
|
||||||
|
/* enable dramc 2X mode */
|
||||||
|
setbits_le32(&ch[channel].ao_regs->ddr2ctl, 1 << 0);
|
||||||
|
|
||||||
|
/* select internal clock path */
|
||||||
|
write32(&ch[channel].ddrphy_regs->peri[0], 0x21 << 24 | 0x27 << 16 |
|
||||||
|
0x1b << 8 | 0x3 << 0);
|
||||||
|
|
||||||
|
write32(&ch[channel].ddrphy_regs->peri[1], 0x50 << 24 | 0x96 << 16 |
|
||||||
|
0x6 << 8 | 0x1e << 0);
|
||||||
|
|
||||||
|
/* trigger to make memory clock correct phase */
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->mempll_divider, 0x1 << 24 |
|
||||||
|
0x1 << 7);
|
||||||
|
|
||||||
|
if(channel == CHANNEL_A) {
|
||||||
|
/* select memory clock sync for channel A (internal source) */
|
||||||
|
clrbits_le32(&ch[channel].ddrphy_regs->mempll_divider, 0x1 << 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mem_pll_init_set_params(u32 channel)
|
||||||
|
{
|
||||||
|
u32 pattern1, pattern2, pattern3;
|
||||||
|
u32 mempll_ic_3_0, mempll_bp_3_0;
|
||||||
|
u32 mempll_fbdiv_6_0, mempll_m4pdiv_1_0;
|
||||||
|
u32 mempll_br_1_0, mempll_bc_1_0, mempll_ir_3_0;
|
||||||
|
|
||||||
|
mempll_fbdiv_6_0 = 0x7 << 16;
|
||||||
|
mempll_br_1_0 = 0x1 << 10;
|
||||||
|
mempll_bc_1_0 = 0x0 << 8;
|
||||||
|
mempll_ir_3_0 = 0xc << 28;
|
||||||
|
mempll_ic_3_0 = 0x6 << 8;
|
||||||
|
mempll_bp_3_0 = 0x1 << 12;
|
||||||
|
mempll_m4pdiv_1_0 = 0x0 << 28;
|
||||||
|
|
||||||
|
write32(&ch[channel].ddrphy_regs->mempll[14], 0x0);
|
||||||
|
|
||||||
|
write32(&ch[channel].ddrphy_regs->mempll[3], 0x3 << 30 |
|
||||||
|
0x1 << 28);
|
||||||
|
/* mempll 2 config */
|
||||||
|
pattern1 = mempll_ir_3_0 | mempll_fbdiv_6_0 | mempll_ic_3_0;
|
||||||
|
pattern2 = mempll_m4pdiv_1_0;
|
||||||
|
pattern3 = mempll_bp_3_0 | mempll_br_1_0 | mempll_bc_1_0;
|
||||||
|
|
||||||
|
/* mempll2_autok_en = 1, mempll2_autok_load = 1 */
|
||||||
|
write32(&ch[channel].ddrphy_regs->mempll[5], 0x1 << 26 | 0x3 << 24 |
|
||||||
|
0x1 << 23 | pattern1);
|
||||||
|
write32(&ch[channel].ddrphy_regs->mempll[6], 0x1 << 30 | 0x3 << 26 |
|
||||||
|
0x3 << 14 | pattern2);
|
||||||
|
write32(&ch[channel].ddrphy_regs->mempll[7], 0x1 << 17 | 0x1 << 0 |
|
||||||
|
pattern3);
|
||||||
|
/* mempll 4 */
|
||||||
|
write32(&ch[channel].ddrphy_regs->mempll[11], 0x1 << 26 | 0x3 << 24 |
|
||||||
|
0x1 << 23 | pattern1);
|
||||||
|
write32(&ch[channel].ddrphy_regs->mempll[12], 0x1 << 30 | 0x3 << 26 |
|
||||||
|
0x3 << 14 | pattern2);
|
||||||
|
write32(&ch[channel].ddrphy_regs->mempll[13], 0x1 << 0 | pattern3);
|
||||||
|
|
||||||
|
/* mempll 3 - enable signal tie together */
|
||||||
|
write32(&ch[channel].ddrphy_regs->mempll[8], 0x1 << 26 | 0x3 << 24 |
|
||||||
|
0x1 << 23 | pattern1);
|
||||||
|
write32(&ch[channel].ddrphy_regs->mempll[9], 0x1 << 30 | 0x3 << 26 |
|
||||||
|
0x3 << 14 | pattern2);
|
||||||
|
write32(&ch[channel].ddrphy_regs->mempll[10], 0x1 << 17 | 0x1 << 0 |
|
||||||
|
pattern3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mem_pll_init_phase_sync(u32 channel)
|
||||||
|
{
|
||||||
|
write32(&ch[channel].ddrphy_regs->mempll_divider, BIT(27) | BIT(24) |
|
||||||
|
BIT(7) | BIT(5) |
|
||||||
|
BIT(4) | BIT(0));
|
||||||
|
/* spm control clock enable */
|
||||||
|
clrsetbits_le32(&ch[channel].ddrphy_regs->mempll_divider, BIT(0),
|
||||||
|
BIT(1));
|
||||||
|
|
||||||
|
clrsetbits_le32(&ch[channel].ddrphy_regs->mempll_divider, BIT(1),
|
||||||
|
BIT(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pll_phase_adjust(u32 channel, struct mem_pll *mempll, int reg_offs)
|
||||||
|
{
|
||||||
|
switch (mempll->phase) {
|
||||||
|
|
||||||
|
case MEMPLL_INIT:
|
||||||
|
/* initial phase: zero out RG_MEPLL(2,3,4)_(REF_DL,FB)_DL */
|
||||||
|
clrbits_le32(&ch[channel].ddrphy_regs->mempll[reg_offs],
|
||||||
|
0x1f << MEMPLL_REF_DL_SHIFT |
|
||||||
|
0x1f << MEMPLL_FB_DL_SHIFT);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MEMPLL_REF_LAG:
|
||||||
|
/* REF lag FBK, delay FBK */
|
||||||
|
clrsetbits_le32(&ch[channel].ddrphy_regs->mempll[reg_offs],
|
||||||
|
0x1f << MEMPLL_REF_DL_SHIFT |
|
||||||
|
0x1f << MEMPLL_FB_DL_SHIFT,
|
||||||
|
mempll->delay << MEMPLL_FB_DL_SHIFT);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MEMPLL_REF_LEAD:
|
||||||
|
/* REF lead FBK, delay REF */
|
||||||
|
clrsetbits_le32(&ch[channel].ddrphy_regs->mempll[reg_offs],
|
||||||
|
0x1f << MEMPLL_REF_DL_SHIFT |
|
||||||
|
0x1f << MEMPLL_FB_DL_SHIFT,
|
||||||
|
mempll->delay << MEMPLL_REF_DL_SHIFT);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pll_phase_check(u32 channel, struct mem_pll *mempll, int idx)
|
||||||
|
{
|
||||||
|
u32 value = read32(&ch[channel].ddrphy_regs->jmeter_pll_st[idx]);
|
||||||
|
u16 one_count = (u16)((value >> 16) & 0xffff);
|
||||||
|
u16 zero_count = (u16)(value & 0xffff);
|
||||||
|
|
||||||
|
dramc_dbg_msg("PLL %d, phase %d, one_count %d, zero_count %d\n",
|
||||||
|
(idx + 2), mempll->phase, one_count, zero_count);
|
||||||
|
|
||||||
|
switch (mempll->phase) {
|
||||||
|
|
||||||
|
case MEMPLL_INIT:
|
||||||
|
if ((one_count - zero_count) > JMETER_COUNT_N) {
|
||||||
|
/* REF lag FBK */
|
||||||
|
mempll->phase = MEMPLL_REF_LAG;
|
||||||
|
mempll->delay++;
|
||||||
|
} else if ((zero_count - one_count) > JMETER_COUNT_N) {
|
||||||
|
/* REF lead FBK */
|
||||||
|
mempll->phase = MEMPLL_REF_LEAD;
|
||||||
|
mempll->delay++;
|
||||||
|
} else {
|
||||||
|
/* in-phase at initial */
|
||||||
|
mempll->done = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MEMPLL_REF_LAG:
|
||||||
|
if (JMETER_COUNT_N >= (one_count - zero_count)) {
|
||||||
|
mempll->done = 1;
|
||||||
|
} else {
|
||||||
|
mempll->delay++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MEMPLL_REF_LEAD:
|
||||||
|
if (JMETER_COUNT_N >= (zero_count - one_count)) {
|
||||||
|
mempll->done = 1;
|
||||||
|
} else {
|
||||||
|
mempll->delay++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mem_pll_phase_cali(u32 channel)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
struct mem_pll mempll[3] =
|
||||||
|
{
|
||||||
|
{0, 0, 0},
|
||||||
|
{0, 0, 0},
|
||||||
|
{0, 0, 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
dramc_dbg_msg("[PLL_Phase_Calib] ===== PLL Phase Calibration: ");
|
||||||
|
dramc_dbg_msg("CHANNEL %d (0: CHA, 1: CHB) =====\n", channel);
|
||||||
|
|
||||||
|
/* 1. set jitter meter count number to 1024 for mempll 2 3 4 */
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
clrsetbits_le32(&ch[channel].ddrphy_regs->jmeter[i],
|
||||||
|
JMETER_COUNTER_MASK,
|
||||||
|
JMETER_COUNT << JMETER_COUNTER_SHIFT);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
if (!mempll[i].done) {
|
||||||
|
pll_phase_adjust(channel, &mempll[i], (i + 2) * 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
udelay(20); /* delay 20us for external loop pll stable */
|
||||||
|
|
||||||
|
/* 2. enable mempll 2 3 4 jitter meter */
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->jmeter[i],
|
||||||
|
JMETER_EN_BIT);
|
||||||
|
|
||||||
|
/* 3. wait for jitter meter complete */
|
||||||
|
udelay(JMETER_WAIT_DONE_US);
|
||||||
|
|
||||||
|
/* 4. check jitter meter counter value for mempll 2 3 4 */
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
if (!mempll[i].done) {
|
||||||
|
pll_phase_check(channel, &mempll[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 5. disable mempll 2 3 4 jitter meter */
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
clrbits_le32(&ch[channel].ddrphy_regs->jmeter[i],
|
||||||
|
JMETER_EN_BIT);
|
||||||
|
|
||||||
|
/* 6. all done early break */
|
||||||
|
if (mempll[0].done && mempll[1].done && mempll[2].done)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* 7. delay line overflow break */
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
if(mempll[i].delay >= 32) {
|
||||||
|
die("MEMPLL calibration fail\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dramc_dbg_msg("pll done: ");
|
||||||
|
|
||||||
|
dramc_dbg_msg("%d, %d, %d\n",
|
||||||
|
mempll[0].done, mempll[1].done, mempll[2].done);
|
||||||
|
dramc_dbg_msg("pll dl: %d, %d, %d\n",
|
||||||
|
mempll[0].delay, mempll[1].delay, mempll[2].delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_pll_init(const struct mt8173_sdram_params *sdram_params)
|
||||||
|
{
|
||||||
|
u32 channel;
|
||||||
|
|
||||||
|
/* udelay waits for PLL to stabilize in this function */
|
||||||
|
printk(BIOS_DEBUG, "[PLL] mempll_init and cali\n");
|
||||||
|
|
||||||
|
/* mempll pre_init for two channels */
|
||||||
|
for (channel = 0; channel < CHANNEL_NUM; channel++)
|
||||||
|
mem_pll_pre_init(channel);
|
||||||
|
|
||||||
|
/* only set once in MPLL */
|
||||||
|
mt_mem_pll_config_pre(sdram_params);
|
||||||
|
|
||||||
|
for (channel = 0; channel < CHANNEL_NUM; channel++)
|
||||||
|
mem_pll_init_set_params(channel);
|
||||||
|
|
||||||
|
udelay(1); /* wait after da_mpll_sdm_iso_en goes low */
|
||||||
|
|
||||||
|
/* only set once in MPLL */
|
||||||
|
mt_mem_pll_config_post();
|
||||||
|
|
||||||
|
udelay(100);
|
||||||
|
|
||||||
|
for (channel = 0; channel < CHANNEL_NUM; channel++) {
|
||||||
|
|
||||||
|
/* mempll_bias_en */
|
||||||
|
write32(&ch[channel].ddrphy_regs->mempll[3], 0xd << 28 |
|
||||||
|
0x1 << 6);
|
||||||
|
udelay(2);
|
||||||
|
|
||||||
|
/* mempll2_en -> mempll4_en -> mempll3_en */
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->mempll[5], 1 << 0);
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->mempll[11], 1 << 0);
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->mempll[8], 1 << 0);
|
||||||
|
|
||||||
|
udelay(100);
|
||||||
|
|
||||||
|
/* mempll_bias_lpf_en */
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->mempll[3], 1 << 7);
|
||||||
|
|
||||||
|
udelay(30);
|
||||||
|
|
||||||
|
/* select mempll4 band register */
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->mempll[4], 1 << 26);
|
||||||
|
clrbits_le32(&ch[channel].ddrphy_regs->mempll[4], 1 << 26);
|
||||||
|
|
||||||
|
/* PLL ready */
|
||||||
|
|
||||||
|
/* disable mempll2_en -> mempll4_en -> mempll3_en */
|
||||||
|
clrbits_le32(&ch[channel].ddrphy_regs->mempll[5], 1 << 0);
|
||||||
|
clrbits_le32(&ch[channel].ddrphy_regs->mempll[11], 1 << 0);
|
||||||
|
clrbits_le32(&ch[channel].ddrphy_regs->mempll[8], 1 << 0);
|
||||||
|
|
||||||
|
/* disable autok mempll2_en -> mempll4_en -> mempll3_en */
|
||||||
|
clrbits_le32(&ch[channel].ddrphy_regs->mempll[5], 1 << 23);
|
||||||
|
clrbits_le32(&ch[channel].ddrphy_regs->mempll[11], 1 << 23);
|
||||||
|
clrbits_le32(&ch[channel].ddrphy_regs->mempll[8], 1 << 23);
|
||||||
|
|
||||||
|
udelay(1);
|
||||||
|
|
||||||
|
/* mempll[2->4->3]_fb_mck_sel=1 (switch to outer loop) */
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->mempll[6], 1 << 25);
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->mempll[12], 1 << 25);
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->mempll[9], 1 << 25);
|
||||||
|
|
||||||
|
udelay(1);
|
||||||
|
|
||||||
|
/* enable mempll2_en -> mempll4_en -> mempll3_en */
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->mempll[5], 1 << 0);
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->mempll[11], 1 << 0);
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->mempll[8], 1 << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mempll new power-on */
|
||||||
|
write32(&mt8173_spm->poweron_config_set, 0x1 << 0 |
|
||||||
|
SPM_PROJECT_CODE << 16);
|
||||||
|
/* request mempll reset/pdn mode */
|
||||||
|
setbits_le32(&mt8173_spm->power_on_val0, 0x1 << 27);
|
||||||
|
|
||||||
|
udelay(2);
|
||||||
|
|
||||||
|
/* unrequest mempll reset/pdn mode and wait settle */
|
||||||
|
clrbits_le32(&mt8173_spm->power_on_val0, 0x1 << 27);
|
||||||
|
|
||||||
|
udelay(31); /* PLL ready */
|
||||||
|
|
||||||
|
for (channel = 0; channel < CHANNEL_NUM; channel++)
|
||||||
|
mem_pll_init_phase_sync(channel);
|
||||||
|
|
||||||
|
udelay(1);
|
||||||
|
|
||||||
|
/* mempll calibration for two channels */
|
||||||
|
for (channel = 0; channel < CHANNEL_NUM; channel++)
|
||||||
|
mem_pll_phase_cali(channel);
|
||||||
|
|
||||||
|
div2_phase_sync(); /* phase sync for channel B */
|
||||||
|
|
||||||
|
mt_mem_pll_mux();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dramc_pre_init(u32 channel, const struct mt8173_sdram_params *sdram_params)
|
||||||
|
{
|
||||||
|
/* txdly_cs, txdly_cs1 */
|
||||||
|
write32(&ch[channel].ao_regs->selph1, 0x0);
|
||||||
|
/* txdly_dqsgate, txdly_dqsgate_p1 */
|
||||||
|
write32(&ch[channel].ao_regs->selph2, 0x3 << 20 | 0x2 << 12);
|
||||||
|
/* txldy_ra* */
|
||||||
|
write32(&ch[channel].ao_regs->selph3, 0x0);
|
||||||
|
/* txldy_ra* */
|
||||||
|
write32(&ch[channel].ao_regs->selph4, 0x0);
|
||||||
|
|
||||||
|
/* setting of write latency (WL=8) */
|
||||||
|
write32(&ch[channel].ao_regs->selph7, 0x3333 << 16 | 0x3333);
|
||||||
|
write32(&ch[channel].ao_regs->selph8, 0x3333 << 16 | 0x3333);
|
||||||
|
write32(&ch[channel].ao_regs->selph9, 0x3333 << 16 | 0x3333);
|
||||||
|
write32(&ch[channel].ao_regs->selph10, 0x5555 << 16 | 0xffff);
|
||||||
|
write32(&ch[channel].ao_regs->selph11, 0x55 << 16 | 0xff);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->selph5, 0x1 << 26 | 0x2 << 22 |
|
||||||
|
0x1 << 20 | 0x5 << 16 |
|
||||||
|
0x5555);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->selph6_1, 0x4 << 8 | 0x3 << 4 |
|
||||||
|
0x2 << 0);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->ac_time_05t,
|
||||||
|
sdram_params->ac_timing.actim05t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mrs_write(int channel, int rank, u32 mrs_value, unsigned int dly)
|
||||||
|
{
|
||||||
|
write32(&ch[channel].ao_regs->mrs, rank << 28 | mrs_value);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->spcmd, 0x1);
|
||||||
|
udelay(dly);
|
||||||
|
write32(&ch[channel].ao_regs->spcmd, 0x0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dramc_set_mrs_value(int channel, int rank,
|
||||||
|
const struct mt8173_sdram_params *sdram_params)
|
||||||
|
{
|
||||||
|
/* MR63 -> Reset, Wait >=10us if not check DAI */
|
||||||
|
mrs_write(channel, rank, sdram_params->mrs_set.mrs_63, 10);
|
||||||
|
/* MR10 -> ZQ Init, tZQINIT>=1us */
|
||||||
|
mrs_write(channel, rank, sdram_params->mrs_set.mrs_10, 1);
|
||||||
|
/* MR3 driving stregth set to max */
|
||||||
|
mrs_write(channel, rank, sdram_params->mrs_set.mrs_3, 1);
|
||||||
|
/* MR1 */
|
||||||
|
mrs_write(channel, rank, sdram_params->mrs_set.mrs_1, 1);
|
||||||
|
/* MR2 */
|
||||||
|
mrs_write(channel, rank, sdram_params->mrs_set.mrs_2, 1);
|
||||||
|
/* MR11 ODT disable */
|
||||||
|
mrs_write(channel, rank, sdram_params->mrs_set.mrs_11, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dramc_init(u32 channel, const struct mt8173_sdram_params *sdram_params)
|
||||||
|
{
|
||||||
|
u32 bit, dual_rank_set;
|
||||||
|
|
||||||
|
const struct mt8173_calib_params *calib_params;
|
||||||
|
|
||||||
|
dual_rank_set = is_dual_rank(channel, sdram_params);
|
||||||
|
calib_params = &sdram_params->calib_params;
|
||||||
|
|
||||||
|
write32(&ch[channel].ddrphy_regs->peri[2], 0x1 << 12 |
|
||||||
|
0x1 << 4);
|
||||||
|
|
||||||
|
write32(&ch[channel].ddrphy_regs->peri[3], 0x0);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->test2_4,
|
||||||
|
sdram_params->ac_timing.test2_4);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->clk1delay, 0x1 << 23 |
|
||||||
|
0x1 << 22 |
|
||||||
|
0x1 << 21);
|
||||||
|
|
||||||
|
/* rank config */
|
||||||
|
assert((sdram_params->ac_timing.rkcfg & 0x1) == dual_rank_set);
|
||||||
|
write32(&ch[channel].ao_regs->rkcfg,
|
||||||
|
sdram_params->ac_timing.rkcfg);
|
||||||
|
|
||||||
|
/* pimux */
|
||||||
|
write32(&ch[channel].ao_regs->mckdly, 0x1 << 30 |
|
||||||
|
0x1 << 20 |
|
||||||
|
0x1 << 4);
|
||||||
|
|
||||||
|
write32(&ch[channel].ddrphy_regs->mckdly, 0x1 << 8);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->padctl4, 0x1 << 0);
|
||||||
|
|
||||||
|
/* tCKEH/tCKEL extend 1T */
|
||||||
|
write32(&ch[channel].ao_regs->dummy, 0x1 << 31 |
|
||||||
|
0x3 << 10 |
|
||||||
|
0x1 << 4);
|
||||||
|
|
||||||
|
/* driving control */
|
||||||
|
write32(&ch[channel].ao_regs->iodrv6, DEFAULT_DRIVING |
|
||||||
|
DRIVING_DS2_0 << 20 |
|
||||||
|
DRIVING_DS2_0 << 4);
|
||||||
|
|
||||||
|
write32(&ch[channel].ddrphy_regs->drvctl1, DEFAULT_DRIVING |
|
||||||
|
DRIVING_DS2_0 << 20);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->drvctl1, DEFAULT_DRIVING |
|
||||||
|
DRIVING_DS2_0 << 4);
|
||||||
|
|
||||||
|
/* enable dqs signal output */
|
||||||
|
write32(&ch[channel].ddrphy_regs->ioctl, 0x0);
|
||||||
|
|
||||||
|
/* rank 0 dqs gating delay */
|
||||||
|
write32(&ch[channel].ao_regs->dqsien[0], 0x40 << 24 |
|
||||||
|
0x40 << 16 |
|
||||||
|
0x40 << 8 |
|
||||||
|
0x40 << 0);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->dqsctl1, 0x1 << 28 |
|
||||||
|
0x5 << 24);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->dqsctl2, 0x5 << 0);
|
||||||
|
write32(&ch[channel].ao_regs->phyctl1, 0x1 << 25);
|
||||||
|
write32(&ch[channel].ao_regs->gddr3ctl1, 0x1 << 24);
|
||||||
|
write32(&ch[channel].ddrphy_regs->gddr3ctl1, 0x1 << 28);
|
||||||
|
write32(&ch[channel].ao_regs->arbctl0, 0x80 << 0);
|
||||||
|
|
||||||
|
/* enable clock pad 0 */
|
||||||
|
write32(&ch[channel].ao_regs->clkctl, 0x1 << 28);
|
||||||
|
|
||||||
|
udelay(1);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->conf1,
|
||||||
|
sdram_params->ac_timing.conf1);
|
||||||
|
|
||||||
|
write32(&ch[channel].ddrphy_regs->dqsgctl, 0x1 << 31 |
|
||||||
|
0x1 << 30 |
|
||||||
|
0x1 << 4 |
|
||||||
|
0x1 << 0);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->dqscal0, 0x0);
|
||||||
|
write32(&ch[channel].ddrphy_regs->dqscal0, 0x0);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->actim0,
|
||||||
|
sdram_params->ac_timing.actim);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->misctl0,
|
||||||
|
sdram_params->ac_timing.misctl0);
|
||||||
|
write32(&ch[channel].ddrphy_regs->misctl0,
|
||||||
|
sdram_params->ac_timing.misctl0);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->perfctl0, 0x1 << 20);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->ddr2ctl,
|
||||||
|
sdram_params->ac_timing.ddr2ctl);
|
||||||
|
write32(&ch[channel].ddrphy_regs->ddr2ctl,
|
||||||
|
sdram_params->ac_timing.ddr2ctl);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->misc, 0xb << 8 |
|
||||||
|
0x1 << 7 |
|
||||||
|
0x1 << 6 |
|
||||||
|
0x1 << 5);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->dllconf, 0xf << 28 |
|
||||||
|
0x1 << 24);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->actim1,
|
||||||
|
sdram_params->ac_timing.actim1);
|
||||||
|
|
||||||
|
write32(&ch[channel].ddrphy_regs->dqsisel, 0x0);
|
||||||
|
|
||||||
|
/* disable ODT before ZQ calibration */
|
||||||
|
write32(&ch[channel].ao_regs->wodt, 0x1 << 0);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->padctl4, 0x1 << 2 |
|
||||||
|
0x1 << 0);
|
||||||
|
|
||||||
|
udelay(200); /* tINIT3 > 200us */
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->gddr3ctl1, 0x1 << 24 |
|
||||||
|
0x1 << 20);
|
||||||
|
|
||||||
|
write32(&ch[channel].ddrphy_regs->gddr3ctl1, 0x1 << 28);
|
||||||
|
|
||||||
|
/* set mode register value */
|
||||||
|
dramc_set_mrs_value(channel, 0, sdram_params);
|
||||||
|
|
||||||
|
if (dual_rank_set)
|
||||||
|
dramc_set_mrs_value(channel, 1, sdram_params);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->gddr3ctl1,
|
||||||
|
sdram_params->ac_timing.gddr3ctl1);
|
||||||
|
write32(&ch[channel].ddrphy_regs->gddr3ctl1,
|
||||||
|
sdram_params->ac_timing.gddr3ctl1);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->dramc_pd_ctrl,
|
||||||
|
sdram_params->ac_timing.pd_ctrl);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->padctl4, 0x1 << 0);
|
||||||
|
write32(&ch[channel].ao_regs->perfctl0, 0x1 << 20 | 0x1 << 0);
|
||||||
|
write32(&ch[channel].ao_regs->zqcs, 0xa << 8 | 0x56 << 0);
|
||||||
|
write32(&ch[channel].ddrphy_regs->padctl1, 0x0);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->test2_3,
|
||||||
|
sdram_params->ac_timing.test2_3);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->conf2,
|
||||||
|
sdram_params->ac_timing.conf2);
|
||||||
|
|
||||||
|
write32(&ch[channel].ddrphy_regs->padctl2, 0x0);
|
||||||
|
|
||||||
|
/* DISABLE_DRVREF */
|
||||||
|
write32(&ch[channel].ao_regs->ocdk, 0x0);
|
||||||
|
write32(&ch[channel].ddrphy_regs->ocdk, 0x0);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->r1deldly, 0x12 << 24 |
|
||||||
|
0x12 << 16 |
|
||||||
|
0x12 << 8 |
|
||||||
|
0x12 << 0);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->padctl7, 0x0);
|
||||||
|
|
||||||
|
/* CLKTDN, DS0TDN, DS1TDN, DS2TDN, DS3TDN */
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->tdsel[2], 0x1 << 31 |
|
||||||
|
0x1 << 29 |
|
||||||
|
0x1 << 27 |
|
||||||
|
0x1 << 25 |
|
||||||
|
0x1 << 1);
|
||||||
|
/* DISABLE_PERBANK_REFRESH */
|
||||||
|
clrbits_le32(&ch[channel].ao_regs->rkcfg, 0x1 << 7);
|
||||||
|
|
||||||
|
/* clear R_DMREFTHD to reduce MR4 wait refresh queue time */
|
||||||
|
clrbits_le32(&ch[channel].ao_regs->conf2, 0x7 << 24);
|
||||||
|
|
||||||
|
/* duty default value */
|
||||||
|
write32(&ch[channel].ddrphy_regs->phyclkduty, 0x1 << 28 |
|
||||||
|
0x1 << 16);
|
||||||
|
|
||||||
|
if (!dual_rank_set) {
|
||||||
|
/* single rank, CKE1 always off */
|
||||||
|
setbits_le32(&ch[channel].ao_regs->gddr3ctl1, 0x1 << 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* default dqs rx perbit input delay */
|
||||||
|
write32(&ch[channel].ao_regs->r0deldly,
|
||||||
|
calib_params->rx_dqs_dly[channel]);
|
||||||
|
|
||||||
|
write32(&ch[channel].ao_regs->r1deldly,
|
||||||
|
calib_params->rx_dqs_dly[channel]);
|
||||||
|
|
||||||
|
for (bit = 0; bit < DQS_BIT_NUMBER; bit++)
|
||||||
|
write32(&ch[channel].ao_regs->dqidly[bit],
|
||||||
|
calib_params->rx_dq_dly[channel][bit]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void div2_phase_sync(void)
|
||||||
|
{
|
||||||
|
clrbits_le32(&ch[CHANNEL_B].ddrphy_regs->mempll_divider,
|
||||||
|
1 << MEMCLKENB_SHIFT);
|
||||||
|
udelay(1);
|
||||||
|
|
||||||
|
setbits_le32(&ch[CHANNEL_B].ddrphy_regs->mempll_divider,
|
||||||
|
1 << MEMCLKENB_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dramc_phy_reset(u32 channel)
|
||||||
|
{
|
||||||
|
/* reset phy */
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->phyctl1,
|
||||||
|
1 << PHYCTL1_PHYRST_SHIFT);
|
||||||
|
|
||||||
|
/* read data counter reset */
|
||||||
|
setbits_le32(&ch[channel].ao_regs->gddr3ctl1,
|
||||||
|
1 << GDDR3CTL1_RDATRST_SHIFT);
|
||||||
|
|
||||||
|
udelay(1); /* delay 1ns */
|
||||||
|
|
||||||
|
clrbits_le32(&ch[channel].ao_regs->gddr3ctl1,
|
||||||
|
1 << GDDR3CTL1_RDATRST_SHIFT);
|
||||||
|
|
||||||
|
clrbits_le32(&ch[channel].ddrphy_regs->phyctl1,
|
||||||
|
1 << PHYCTL1_PHYRST_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dramc_runtime_config(u32 channel,
|
||||||
|
const struct mt8173_sdram_params *sdram_params)
|
||||||
|
{
|
||||||
|
/* enable hw gating */
|
||||||
|
setbits_le32(&ch[channel].ao_regs->dqscal0,
|
||||||
|
1 << DQSCAL0_STBCALEN_SHIFT);
|
||||||
|
|
||||||
|
/* if frequency >1600, tCKE should >7 clk */
|
||||||
|
setbits_le32(&ch[channel].ao_regs->dummy, 0x1 << 4);
|
||||||
|
|
||||||
|
if(sdram_params->dram_freq * 2 < 1600 * MHz)
|
||||||
|
die("set tCKE error in runtime config");
|
||||||
|
|
||||||
|
/* DDRPHY C/A and DQ M_CK clock gating enable */
|
||||||
|
setbits_le32(&ch[channel].ddrphy_regs->ddrphy_cg_ctrl, 0x1 << 2 |
|
||||||
|
0x1 << 1);
|
||||||
|
|
||||||
|
setbits_le32(&ch[channel].ao_regs->perfctl0, BIT(19) | BIT(14) |
|
||||||
|
BIT(11) | BIT(10) |
|
||||||
|
BIT(9) | BIT(8) |
|
||||||
|
BIT(4) | BIT(0));
|
||||||
|
/* ZQCS_ENABLE */
|
||||||
|
if (sdram_params->emi_set.cona & 0x1) {
|
||||||
|
/* dual channel, clear ZQCSCNT */
|
||||||
|
clrbits_le32(&ch[channel].ao_regs->spcmd, 0xff << 16);
|
||||||
|
/* set ZQCSMASK for different channels */
|
||||||
|
if (channel == CHANNEL_A) {
|
||||||
|
clrbits_le32(&ch[channel].ao_regs->perfctl0, 0x1 << 24);
|
||||||
|
} else {
|
||||||
|
setbits_le32(&ch[channel].ao_regs->perfctl0, 0x1 << 24);
|
||||||
|
}
|
||||||
|
/* enable ZQCSDUAL */
|
||||||
|
setbits_le32(&ch[channel].ao_regs->perfctl0, 0x1 << 25);
|
||||||
|
} else {
|
||||||
|
/* single channel, set ZQCSCNT */
|
||||||
|
setbits_le32(&ch[channel].ao_regs->spcmd, 0x8 << 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void transfer_to_spm_control(void)
|
||||||
|
{
|
||||||
|
u32 msk;
|
||||||
|
|
||||||
|
msk = BIT(7) | BIT(11) | BIT(15);
|
||||||
|
clrbits_le32(&mt8173_apmixed->ap_pll_con3, msk);
|
||||||
|
|
||||||
|
msk = BIT(0) | BIT(4) | BIT(8);
|
||||||
|
clrbits_le32(&ch[CHANNEL_A].ddrphy_regs->peri[3], msk);
|
||||||
|
|
||||||
|
msk = BIT(0) | BIT(8);
|
||||||
|
clrbits_le32(&ch[CHANNEL_B].ddrphy_regs->peri[3], msk);
|
||||||
|
|
||||||
|
msk = BIT(0) | BIT(9) | BIT(10) | BIT(11) | BIT(16) | BIT(24);
|
||||||
|
clrbits_le32(&ch[CHANNEL_A].ddrphy_regs->peri[2], msk);
|
||||||
|
clrbits_le32(&ch[CHANNEL_B].ddrphy_regs->peri[2], msk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void transfer_to_reg_control(void)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
val = BIT(7) | BIT(11) | BIT(15);
|
||||||
|
setbits_le32(&mt8173_apmixed->ap_pll_con3, val);
|
||||||
|
|
||||||
|
val = BIT(0) | BIT(4) | BIT(8);
|
||||||
|
setbits_le32(&ch[CHANNEL_A].ddrphy_regs->peri[3], val);
|
||||||
|
|
||||||
|
val = BIT(0) | BIT(8);
|
||||||
|
write32(&ch[CHANNEL_B].ddrphy_regs->peri[3], val);
|
||||||
|
|
||||||
|
val = BIT(0) | BIT(9) | BIT(10) | BIT(11) | BIT(16) | BIT(24);
|
||||||
|
setbits_le32(&ch[CHANNEL_A].ddrphy_regs->peri[2], val);
|
||||||
|
setbits_le32(&ch[CHANNEL_B].ddrphy_regs->peri[2], val);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 dramc_engine2(u32 channel, enum dram_tw_op wr, u32 test2_1, u32 test2_2,
|
||||||
|
u8 testaudpat, u8 log2loopcount)
|
||||||
|
{
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
if (log2loopcount > 15)
|
||||||
|
die("Invalid loopcount of engine2!");
|
||||||
|
|
||||||
|
/* Disable Test Agent1, Test Agent2 write/read */
|
||||||
|
clrbits_le32(&ch[channel].ao_regs->conf2, CONF2_TEST1_EN |
|
||||||
|
CONF2_TEST2R_EN |
|
||||||
|
CONF2_TEST2W_EN);
|
||||||
|
|
||||||
|
/* 1. set pattern, base address, offset address */
|
||||||
|
write32(&ch[channel].nao_regs->test2_1, test2_1);
|
||||||
|
write32(&ch[channel].nao_regs->test2_2, test2_2);
|
||||||
|
|
||||||
|
/* 2. select test pattern */
|
||||||
|
/* TESTXTALKPAT | TESTAUDPAT
|
||||||
|
* ISI 0 | 0
|
||||||
|
* AUD 0 | 1
|
||||||
|
* XTALK 1 | 0
|
||||||
|
* UNKNOW 1 | 1
|
||||||
|
*/
|
||||||
|
switch (testaudpat) {
|
||||||
|
case XTALK:
|
||||||
|
/* TESTAUDPAT = 0 */
|
||||||
|
clrbits_le32(&ch[channel].ao_regs->test2_3,
|
||||||
|
TEST2_3_TESTAUDPAT_EN);
|
||||||
|
/* TESTXTALKPAT = 1, select xtalk pattern
|
||||||
|
* TESTAUDMODE = 0, read only
|
||||||
|
* TESTAUDBITINV = 0, no bit inversion
|
||||||
|
*/
|
||||||
|
clrsetbits_le32(&ch[channel].ao_regs->test2_4,
|
||||||
|
TEST2_4_TESTAUDBITINV_EN |
|
||||||
|
TEST2_4_TESTAUDMODE_EN,
|
||||||
|
TEST2_4_TESTXTALKPAT_EN);
|
||||||
|
break;
|
||||||
|
case AUDIO:
|
||||||
|
/* TESTAUDPAT = 1 */
|
||||||
|
setbits_le32(&ch[channel].ao_regs->test2_3,
|
||||||
|
TEST2_3_TESTAUDPAT_EN);
|
||||||
|
/* TESTXTALKPAT = 0
|
||||||
|
* TESTAUDINIT = 0x11
|
||||||
|
* TESTAUDINC = 0x0d
|
||||||
|
* TESTAUDBITINV = 1
|
||||||
|
* TESTAUDMODE = 1
|
||||||
|
*/
|
||||||
|
clrsetbits_le32(&ch[channel].ao_regs->test2_4,
|
||||||
|
TEST2_4_TESTXTALKPAT_EN |
|
||||||
|
TEST2_4_TESTAUDINIT_MASK |
|
||||||
|
TEST2_4_TESTAUDINC_MASK,
|
||||||
|
TEST2_4_TESTAUDMODE_EN |
|
||||||
|
TEST2_4_TESTAUDBITINV_EN |
|
||||||
|
0x11 << TEST2_4_TESTAUDINIT_SHIFT |
|
||||||
|
0xd << TEST2_4_TESTAUDINC_SHIFT);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ISI:
|
||||||
|
/* TESTAUDPAT = 0 */
|
||||||
|
clrbits_le32(&ch[channel].ao_regs->test2_3,
|
||||||
|
TEST2_3_TESTAUDPAT_EN);
|
||||||
|
/* TESTXTALKPAT = 0 */
|
||||||
|
clrbits_le32(&ch[channel].ao_regs->test2_4,
|
||||||
|
TEST2_4_TESTXTALKPAT_EN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. set loop number */
|
||||||
|
clrsetbits_le32(&ch[channel].ao_regs->test2_3, TEST2_3_TESTCNT_MASK,
|
||||||
|
log2loopcount << TEST2_3_TESTCNT_SHIFT);
|
||||||
|
|
||||||
|
/* 4. enable read/write test */
|
||||||
|
if (wr == TE_OP_READ_CHECK) {
|
||||||
|
if ((testaudpat == 1) || (testaudpat == 2)) {
|
||||||
|
/* if audio pattern, enable read only */
|
||||||
|
/* (disable write after read), */
|
||||||
|
/* AUDMODE=0x48[15]=0 */
|
||||||
|
clrbits_le32(&ch[channel].ao_regs->test2_4,
|
||||||
|
TEST2_4_TESTAUDMODE_EN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable read, 0x008[30:30] */
|
||||||
|
setbits_le32(&ch[channel].ao_regs->conf2, CONF2_TEST2R_EN);
|
||||||
|
} else if (wr == TE_OP_WRITE_READ_CHECK) {
|
||||||
|
/* enable write, 0x008[31:31] */
|
||||||
|
setbits_le32(&ch[channel].ao_regs->conf2, CONF2_TEST2W_EN);
|
||||||
|
|
||||||
|
/* check "read data compare ready" bit */
|
||||||
|
do {
|
||||||
|
value = read32(&ch[channel].nao_regs->testrpt);
|
||||||
|
} while ((value & (1 << TESTRPT_DM_CMP_CPT_SHIFT)) == 0);
|
||||||
|
|
||||||
|
/* Disable Test Agent2 write and enable Test Agent2 read */
|
||||||
|
clrbits_le32(&ch[channel].ao_regs->conf2, CONF2_TEST2W_EN);
|
||||||
|
setbits_le32(&ch[channel].ao_regs->conf2, CONF2_TEST2R_EN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 5 check "read data compare ready" bit */
|
||||||
|
do {
|
||||||
|
value = read32(&ch[channel].nao_regs->testrpt);
|
||||||
|
} while ((value & (1 << TESTRPT_DM_CMP_CPT_SHIFT)) == 0);
|
||||||
|
|
||||||
|
/* delay 10ns after ready check from DE suggestion (1us here) */
|
||||||
|
udelay(1);
|
||||||
|
|
||||||
|
/* read CMP_ERR result */
|
||||||
|
value = read32(&ch[channel].nao_regs->cmp_err);
|
||||||
|
|
||||||
|
/* 6 disable read */
|
||||||
|
clrbits_le32(&ch[channel].ao_regs->conf2, CONF2_TEST2R_EN);
|
||||||
|
|
||||||
|
/* return CMP_ERR result, pass: 0, failure: otherwise */
|
||||||
|
return value;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _DRAMC_COMMON_H_
|
||||||
|
#define _DRAMC_COMMON_H_
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CHANNEL_A = 0,
|
||||||
|
CHANNEL_B,
|
||||||
|
CHANNEL_NUM
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
GW_PARAM_COARSE = 0,
|
||||||
|
GW_PARAM_FINE,
|
||||||
|
GW_PARAM_NUM
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DUAL_RANKS = 2,
|
||||||
|
CATRAINING_NUM = 10
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DQ_DATA_WIDTH = 32,
|
||||||
|
DQS_BIT_NUMBER = 8,
|
||||||
|
DQS_NUMBER = (DQ_DATA_WIDTH / DQS_BIT_NUMBER)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _DRAMC_COMMON_H_ */
|
|
@ -0,0 +1,187 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _DRAMC_PI_API_H
|
||||||
|
#define _DRAMC_PI_API_H
|
||||||
|
|
||||||
|
#include <soc/emi.h>
|
||||||
|
#include <console/console.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MAX_CLKO_DELAY = 15
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* jitter meter for PLL phase calibration */
|
||||||
|
JMETER_COUNT = 1024,
|
||||||
|
JMETER_COUNT_N = JMETER_COUNT/10,
|
||||||
|
/* 10us for more margin, Fin = 52 */
|
||||||
|
JMETER_WAIT_DONE_US = (JMETER_COUNT/52 + 10)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DLE_TEST_NUM = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* window type: tx/rx */
|
||||||
|
RX_WIN = 0,
|
||||||
|
TX_WIN = 1,
|
||||||
|
/* stage type: setup/hold time */
|
||||||
|
STAGE_SETUP = 0,
|
||||||
|
STAGE_HOLD = 1,
|
||||||
|
/* combinational flags of stage and window type */
|
||||||
|
STAGE_SETUP_RX_WIN = STAGE_SETUP | RX_WIN << 1,
|
||||||
|
STAGE_SETUP_TX_WIN = STAGE_SETUP | TX_WIN << 1,
|
||||||
|
STAGE_HOLD_RX_WIN = STAGE_HOLD | RX_WIN << 1,
|
||||||
|
STAGE_HOLD_TX_WIN = STAGE_HOLD | TX_WIN << 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
RX_DQ = 0,
|
||||||
|
RX_DQS,
|
||||||
|
TX_DQ,
|
||||||
|
TX_DQS,
|
||||||
|
TX_DQM
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
AUDIO = 1,
|
||||||
|
XTALK,
|
||||||
|
ISI
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MEMPLL_INIT = 0,
|
||||||
|
MEMPLL_REF_LAG,
|
||||||
|
MEMPLL_REF_LEAD
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FIRST_DQ_DELAY = 0, /* first DQ delay taps */
|
||||||
|
FIRST_DQS_DELAY = 0, /* first DQS delay taps */
|
||||||
|
MAX_DQDLY_TAPS = 16, /* max DQ delay taps */
|
||||||
|
MAX_TX_DQSDLY_TAPS = 16, /* max TX DQS delay taps */
|
||||||
|
MAX_RX_DQSDLY_TAPS = 64 /* max RX DQS delay taps */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DRAMK_READ = 0,
|
||||||
|
DRAMK_WRITE = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ENABLE = 1,
|
||||||
|
DISABLE = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DATA_WIDTH_16BIT = 16,
|
||||||
|
DATA_WIDTH_32BIT = 32
|
||||||
|
};
|
||||||
|
|
||||||
|
enum dram_tw_op {
|
||||||
|
TE_OP_WRITE_READ_CHECK = 0,
|
||||||
|
TE_OP_READ_CHECK
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DQS_GW_TE_OFFSET = 0x10,
|
||||||
|
DQS_GW_GOLD_COUNTER_32BIT = 0x20202020,
|
||||||
|
DQS_GW_PATTERN1 = 0xaa000000,
|
||||||
|
DQS_GW_PATTERN2 = 0x55000000
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* pattern0 and base address for test engine when we do calibration */
|
||||||
|
DEFAULT_TEST2_1_CAL = 0x55000000,
|
||||||
|
/* for testing, to separate TA4-3 address for running simultaneously */
|
||||||
|
/* pattern1 and offset address for test engine when we do calibraion */
|
||||||
|
DEFAULT_TEST2_2_CAL = 0xaa000400,
|
||||||
|
/* pattern0 and base addr. for test engine when doing dqs GW */
|
||||||
|
DEFAULT_TEST2_1_DQSIEN = 0x55000000,
|
||||||
|
/* pattern1 and offset addr. for test engine when doing dqs GW */
|
||||||
|
DEFAULT_TEST2_2_DQSIEN = 0xaa000010,
|
||||||
|
/* gold pattern */
|
||||||
|
DEFAULT_GOLD_DQSIEN = 0x20202020
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TEST_ISI_PATTERN = 0,
|
||||||
|
TEST_AUDIO_PATTERN,
|
||||||
|
TEST_TA1_SIMPLE,
|
||||||
|
TEST_TESTPAT4,
|
||||||
|
TEST_TESTPAT4_3,
|
||||||
|
TEST_XTALK_PATTERN,
|
||||||
|
TEST_MIX_PATTERN
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dqs_perbit_dly {
|
||||||
|
s8 first_dqdly_pass;
|
||||||
|
s8 last_dqdly_pass;
|
||||||
|
s8 first_dqsdly_pass;
|
||||||
|
s8 last_dqsdly_pass;
|
||||||
|
s8 best_first_dqdly_pass;
|
||||||
|
s8 best_last_dqdly_pass;
|
||||||
|
s8 best_first_dqsdly_pass;
|
||||||
|
s8 best_last_dqsdly_pass;
|
||||||
|
u8 best_dqdly;
|
||||||
|
u8 best_dqsdly;
|
||||||
|
};
|
||||||
|
|
||||||
|
void transfer_to_spm_control(void);
|
||||||
|
void transfer_to_reg_control(void);
|
||||||
|
void dramc_phy_reset(u32 channel);
|
||||||
|
void clk_duty_cal(u32 channel);
|
||||||
|
void div2_phase_sync(void);
|
||||||
|
void dramc_runtime_config(u32 channel, const struct mt8173_sdram_params *sdram_params);
|
||||||
|
void dramc_rankinctl_config(u32 channel, const struct mt8173_sdram_params *sdram_params);
|
||||||
|
|
||||||
|
/* dramc init prototypes */
|
||||||
|
void mem_pll_init(const struct mt8173_sdram_params *sdram_params);
|
||||||
|
void dramc_init(u32 channel, const struct mt8173_sdram_params *sdram_params);
|
||||||
|
void dramc_pre_init(u32 channel, const struct mt8173_sdram_params *sdram_params);
|
||||||
|
|
||||||
|
/* mandatory calibration function prototypes */
|
||||||
|
void tx_window_perbit_cal(u32 channel);
|
||||||
|
void rx_window_perbit_cal(u32 channel);
|
||||||
|
void perbit_window_cal(u32 channel, u8 type);
|
||||||
|
void sw_impedance_cal(u32 channel, const struct mt8173_sdram_params *sdram_params);
|
||||||
|
void ca_training(u32 channel, const struct mt8173_sdram_params *sdram_params);
|
||||||
|
void rx_dqs_gating_cal(u32 channel, u8 rank, const struct mt8173_sdram_params *sdram_params);
|
||||||
|
void dual_rank_rx_datlat_cal(u32 channel, const struct mt8173_sdram_params *sdram_params);
|
||||||
|
void dual_rank_rx_dqs_gating_cal(u32 channel, const struct mt8173_sdram_params *sdram_params);
|
||||||
|
void write_leveling(u32 channel, const struct mt8173_sdram_params *sdram_params);
|
||||||
|
|
||||||
|
u8 dramk_calcu_best_dly(u8 bit, struct dqs_perbit_dly *p, u8 *p_max_byte);
|
||||||
|
u8 is_dual_rank(u32 channel, const struct mt8173_sdram_params *sdram_params);
|
||||||
|
u8 rx_datlat_cal(u32 channel, u8 rank, const struct mt8173_sdram_params *sdram_params);
|
||||||
|
u32 dram_k_perbit(u32 channel);
|
||||||
|
u32 dramc_engine2(u32 channel, enum dram_tw_op wr, u32 test2_1, u32 test2_2,
|
||||||
|
u8 testaudpat, u8 log2loopcount);
|
||||||
|
|
||||||
|
void dramk_check_dqs_win(struct dqs_perbit_dly *p, u8 dly_step, u8 last_step, u32 fail_bit);
|
||||||
|
void dramk_check_dq_win(struct dqs_perbit_dly *p, u8 dly_step, u8 last_step, u32 fail_bit);
|
||||||
|
|
||||||
|
void tx_delay_for_wrleveling(u32 channel, struct dqs_perbit_dly *dqdqs_perbit_dly,
|
||||||
|
u8 *ave_dqdly_byte, u8 *max_dqsdly_byte);
|
||||||
|
|
||||||
|
#if CONFIG_DEBUG_DRAM
|
||||||
|
#define dramc_dbg_msg(_x_...) printk(BIOS_DEBUG, _x_)
|
||||||
|
#else
|
||||||
|
#define dramc_dbg_msg(_x_...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _PI_API_H */
|
|
@ -0,0 +1,522 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _DRAMC_REGISTER_H_
|
||||||
|
#define _DRAMC_REGISTER_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
#define DRIVING_DS2_0 7 /* DS[2:0] 7->6 */
|
||||||
|
#define DEFAULT_DRIVING 0x99009900
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* CONF2 = 0x008 */
|
||||||
|
CONF2_TEST1_EN = BIT(29),
|
||||||
|
CONF2_TEST2R_EN = BIT(30),
|
||||||
|
CONF2_TEST2W_EN = BIT(31),
|
||||||
|
/* PADCTL1 = 0x00c */
|
||||||
|
PADCTL1_CLK_SHIFT = 24,
|
||||||
|
PADCTL1_CS1_SHIFT = 28,
|
||||||
|
/* PADCTL2 = 0x010 */
|
||||||
|
MASK_PADCTL2_16BIT = 0x000000ff,
|
||||||
|
MASK_PADCTL2_32BIT = 0x0000ffff,
|
||||||
|
MASK_PADCTL2 = 0xffff0000,
|
||||||
|
PADCTL2_SHIFT = 0,
|
||||||
|
/* TEST2_3 = 0x044 */
|
||||||
|
TEST2_3_TESTCNT_SHIFT = 0,
|
||||||
|
TEST2_3_TESTCNT_MASK = (0xful << TEST2_3_TESTCNT_SHIFT),
|
||||||
|
TEST2_3_TESTAUDPAT_EN = BIT(7),
|
||||||
|
TEST2_3_ADVREFEN_EN = BIT(30),
|
||||||
|
/* TEST2_4 = 0x048 */
|
||||||
|
TEST2_4_TESTAUDINC_SHIFT = 0,
|
||||||
|
TEST2_4_TESTAUDINC_MASK = (0x1ful << TEST2_4_TESTAUDINC_SHIFT),
|
||||||
|
TEST2_4_TESTAUDINIT_SHIFT = 8,
|
||||||
|
TEST2_4_TESTAUDINIT_MASK = (0x1ful << TEST2_4_TESTAUDINIT_SHIFT),
|
||||||
|
TEST2_4_TESTAUDBITINV_EN = BIT(14),
|
||||||
|
TEST2_4_TESTAUDMODE_EN = BIT(15),
|
||||||
|
TEST2_4_TESTXTALKPAT_EN = BIT(16),
|
||||||
|
/* DDR2CTL = 0x07c */
|
||||||
|
DDR2CTL_WOEN_SHIFT = 3,
|
||||||
|
DDR2CTL_DATLAT_SHIFT = 4,
|
||||||
|
/* MISC = 0x80 */
|
||||||
|
MISC_LATNORMP_SHIFT = 0,
|
||||||
|
MISC_DATLAT_DSEL_SHIFT = 8,
|
||||||
|
/* MRS = 0x088 */
|
||||||
|
MASK_MR2_OP = 0x00800000,
|
||||||
|
/* R0 R1 DQSIEN = 0x094 */
|
||||||
|
DQSIEN_DQS0IEN_SHIFT = 0,
|
||||||
|
DQSIEN_DQS1IEN_SHIFT = 8,
|
||||||
|
DQSIEN_DQS2IEN_SHIFT = 16,
|
||||||
|
DQSIEN_DQS3IEN_SHIFT = 24,
|
||||||
|
/* MCKDLY = 0x0d8 */
|
||||||
|
MCKDLY_DQIENLAT_SHIFT = 4,
|
||||||
|
MCKDLY_DQIENQKEND_SHIFT = 10,
|
||||||
|
MCKDLY_FIXDQIEN_SHIFT = 12,
|
||||||
|
MCKDLY_FIXODT_SHIFT = 23,
|
||||||
|
/* DQSCTL1 = 0x0e0 */
|
||||||
|
DQSCTL1_DQSINCTL_SHIFT = 24,
|
||||||
|
DQSCTL1_DQSIENMODE_SHIFT = 28,
|
||||||
|
/* PADCTL4 = 0x0e4 */
|
||||||
|
PADCTL4_CKEFIXON_SHIFT = 2,
|
||||||
|
PADCTL4_DATLAT3_SHIFT = 4,
|
||||||
|
/* PHYCTL1 = 0x0f0 */
|
||||||
|
PHYCTL1_DATLAT4_SHIFT = 25,
|
||||||
|
PHYCTL1_PHYRST_SHIFT = 28,
|
||||||
|
/* GDDR3CTL1 = 0x0f4 */
|
||||||
|
GDDR3CTL1_BKSWAP_SHIFT = 20,
|
||||||
|
GDDR3CTL1_RDATRST_SHIFT = 25,
|
||||||
|
GDDR3CTL1_DQMSWAP_SHIFT = 31,
|
||||||
|
/* RKCFG = 0x110 */
|
||||||
|
MASK_RKCFG_RKSWAP_EN = 0x08,
|
||||||
|
RKCFG_PBREF_DISBYRATE_SHIFT = 6,
|
||||||
|
RKCFG_WDATKEY64_SHIFT = 29,
|
||||||
|
/* DQSCTL2 = 0x118 */
|
||||||
|
DQSCTL2_DQSINCTL_SHIFT = 0,
|
||||||
|
/* DQSGCTL = 0x124 */
|
||||||
|
DQSGCTL_DQSGDUALP_SHIFT = 30,
|
||||||
|
/* PHYCLKDUTY = 0x148 */
|
||||||
|
PHYCLKDUTY_CMDCLKP0DUTYN_SHIFT = 16,
|
||||||
|
PHYCLKDUTY_CMDCLKP0DUTYP_SHIFT = 18,
|
||||||
|
PHYCLKDUTY_CMDCLKP0DUTYSEL_SHIFT = 28,
|
||||||
|
/* CMDDLY0 = 0x1a8 */
|
||||||
|
CMDDLY0_RA0_SHIFT = 0,
|
||||||
|
CMDDLY0_RA1_SHIFT = 8,
|
||||||
|
CMDDLY0_RA2_SHIFT = 16,
|
||||||
|
CMDDLY0_RA3_SHIFT = 24,
|
||||||
|
/* CMDDLY1 = 0x1ac */
|
||||||
|
CMDDLY1_RA7_SHIFT = 24,
|
||||||
|
/* CMDDLY3 = 0x1b4 */
|
||||||
|
CMDDLY3_BA0_SHIFT = 8,
|
||||||
|
CMDDLY3_BA1_SHIFT = 16,
|
||||||
|
CMDDLY3_BA2_SHIFT = 24,
|
||||||
|
/* CMDDLY4 = 0x1b8 */
|
||||||
|
CMDDLY4_CS_SHIFT = 0,
|
||||||
|
CMDDLY4_CKE_SHIFT = 8,
|
||||||
|
CMDDLY4_RAS_SHIFT = 16,
|
||||||
|
CMDDLY4_CAS_SHIFT = 24,
|
||||||
|
/* CMDDLY5 = 0x1bc */
|
||||||
|
CMDDLY5_WE_SHIFT = 8,
|
||||||
|
CMDDLY5_RA13_SHIFT = 16,
|
||||||
|
/* DQSCAL0 = 0x1c0 */
|
||||||
|
DQSCAL0_RA14_SHIFT = 24,
|
||||||
|
DQSCAL0_STBCALEN_SHIFT = 31,
|
||||||
|
/* DQSCAL1 = 0x1c4 */
|
||||||
|
DQSCAL1_CKE1_SHIFT = 24,
|
||||||
|
/* IMPCAL = 0x1c8 */
|
||||||
|
IMP_CALI_EN_SHIFT = 0,
|
||||||
|
IMP_CALI_HW_SHIFT = 1,
|
||||||
|
IMP_CALI_ENN_SHIFT = 4,
|
||||||
|
IMP_CALI_ENP_SHIFT = 5,
|
||||||
|
IMP_CALI_PDN_SHIFT = 6,
|
||||||
|
IMP_CALI_PDP_SHIFT = 7,
|
||||||
|
IMP_CALI_DRVP_SHIFT = 8,
|
||||||
|
IMP_CALI_DRVN_SHIFT = 12,
|
||||||
|
/* JMETER for PLL2, PLL3, PLL4 */
|
||||||
|
JMETER_EN_BIT= BIT(0),
|
||||||
|
JMETER_COUNTER_SHIFT = 16,
|
||||||
|
JMETER_COUNTER_MASK = (0xffff << JMETER_COUNTER_SHIFT),
|
||||||
|
/* SPCMD = 0x1e4 */
|
||||||
|
SPCMD_MRWEN_SHIFT = 0,
|
||||||
|
SPCMD_DQSGCNTEN_SHIFT = 8,
|
||||||
|
SPCMD_DQSGCNTRST_SHIFT = 9,
|
||||||
|
/* JMETER for PLL2/3/4 ST */
|
||||||
|
JMETER_PLL_ZERO_SHIFT = 0,
|
||||||
|
JMETER_PLL_ONE_SHIFT = 16,
|
||||||
|
/* TESTRPT = 0x3fc */
|
||||||
|
TESTRPT_DM_CMP_CPT_SHIFT = 10,
|
||||||
|
TESTRPT_DM_CMP_ERR_SHIFT = 14,
|
||||||
|
/* SELPH2 = 0x404 */
|
||||||
|
SELPH2_TXDLY_DQSGATE_SHIFT = 12,
|
||||||
|
SELPH2_TXDLY_DQSGATE_P1_SHIFT = 20,
|
||||||
|
/* SELPH5 = 0x410 */
|
||||||
|
SELPH5_DLY_DQSGATE_SHIFT = 22,
|
||||||
|
SELPH5_DLY_DQSGATE_P1_SHIFT = 24,
|
||||||
|
/* SELPH6_1 = 0x418 */
|
||||||
|
SELPH6_1_DLY_R1DQSGATE_SHIFT = 0,
|
||||||
|
SELPH6_1_DLY_R1DQSGATE_P1_SHIFT = 2,
|
||||||
|
SELPH6_1_TXDLY_R1DQSGATE_SHIFT = 4,
|
||||||
|
SELPH6_1_TXDLY_R1DQSGATE_P1_SHIFT = 8,
|
||||||
|
/* MEMPLL_S14 = 0x638 */
|
||||||
|
MASK_MEMPLL_DL = 0xc0ffffff,
|
||||||
|
MEMPLL_FB_DL_SHIFT = 0,
|
||||||
|
MEMPLL_REF_DL_SHIFT = 8,
|
||||||
|
MEMPLL_DL_SHIFT = 24,
|
||||||
|
MEMPLL_MODE_SHIFT = 29,
|
||||||
|
/* MEMPLL_DIVIDER = 0x640 */
|
||||||
|
MEMCLKENB_SHIFT = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dramc_ao_regs {
|
||||||
|
uint32_t actim0; /* 0x0 */
|
||||||
|
uint32_t conf1; /* 0x4 */
|
||||||
|
uint32_t conf2; /* 0x8 */
|
||||||
|
uint32_t rsvd_ao1[3]; /* 0xc */
|
||||||
|
uint32_t r0deldly; /* 0x18 */
|
||||||
|
uint32_t r1deldly; /* 0x1c */
|
||||||
|
uint32_t r0difdly; /* 0x20 */
|
||||||
|
uint32_t r1difdly; /* 0x24 */
|
||||||
|
uint32_t dllconf; /* 0x28 */
|
||||||
|
uint32_t rsvd_ao2[6]; /* 0x2c */
|
||||||
|
uint32_t test2_3; /* 0x44 */
|
||||||
|
uint32_t test2_4; /* 0x48 */
|
||||||
|
uint32_t catraining; /* 0x4c */
|
||||||
|
uint32_t catraining2; /* 0x50 */
|
||||||
|
uint32_t wodt; /* 0x54 */
|
||||||
|
uint32_t rsvd_ao3[9]; /* 0x58 */
|
||||||
|
uint32_t ddr2ctl; /* 0x7c */
|
||||||
|
uint32_t misc; /* 0x80 */
|
||||||
|
uint32_t zqcs; /* 0x84 */
|
||||||
|
uint32_t mrs; /* 0x88 */
|
||||||
|
uint32_t clk1delay; /* 0x8c */
|
||||||
|
uint32_t rsvd_ao4[1]; /* 0x90 */
|
||||||
|
uint32_t dqsien[2]; /* 0x94 */
|
||||||
|
uint32_t rsvd_ao5[2]; /* 0x9c */
|
||||||
|
uint32_t iodrv1; /* 0xa4 */
|
||||||
|
uint32_t iodrv2; /* 0xa8 */
|
||||||
|
uint32_t iodrv3; /* 0xac */
|
||||||
|
uint32_t iodrv4; /* 0xb0 */
|
||||||
|
uint32_t iodrv5; /* 0xb4 */
|
||||||
|
uint32_t iodrv6; /* 0xb8 */
|
||||||
|
uint32_t drvctl1; /* 0xbc */
|
||||||
|
uint32_t dllsel; /* 0xc0 */
|
||||||
|
uint32_t rsvd_ao7[5]; /* 0xc4 */
|
||||||
|
uint32_t mckdly; /* 0xd8 */
|
||||||
|
uint32_t rsvd_ao8[1]; /* 0xdc */
|
||||||
|
uint32_t dqsctl1; /* 0xe0 */
|
||||||
|
uint32_t padctl4; /* 0xe4 */
|
||||||
|
uint32_t rsvd_ao9[2]; /* 0xe8 */
|
||||||
|
uint32_t phyctl1; /* 0xf0 */
|
||||||
|
uint32_t gddr3ctl1; /* 0xf4 */
|
||||||
|
uint32_t padctl7; /* 0xf8 */
|
||||||
|
uint32_t misctl0; /* 0xfc */
|
||||||
|
uint32_t ocdk; /* 0x100 */
|
||||||
|
uint32_t rsvd_ao10[3]; /* 0x104 */
|
||||||
|
uint32_t rkcfg; /* 0x110 */
|
||||||
|
uint32_t ckphdet; /* 0x114 */
|
||||||
|
uint32_t dqsctl2; /* 0x118 */
|
||||||
|
uint32_t rsvd_ao11[5]; /* 0x11c */
|
||||||
|
uint32_t clkctl; /* 0x130 */
|
||||||
|
uint32_t rsvd_ao12[1]; /* 0x134 */
|
||||||
|
uint32_t dummy; /* 0x138 */
|
||||||
|
uint32_t write_leveling; /* 0x13c */
|
||||||
|
uint32_t rsvd_ao13[10]; /* 0x140 */
|
||||||
|
uint32_t arbctl0; /* 0x168 */
|
||||||
|
uint32_t rsvd_ao14[21]; /* 0x16c */
|
||||||
|
uint32_t dqscal0; /* 0x1c0 */
|
||||||
|
uint32_t dqscal1; /* 0x1c4 */
|
||||||
|
uint32_t impcal; /* 0x1c8 */
|
||||||
|
uint32_t rsvd_ao15[4]; /* 0x1cc */
|
||||||
|
uint32_t dramc_pd_ctrl; /* 0x1dc */
|
||||||
|
uint32_t lpddr2_3; /* 0x1e0 */
|
||||||
|
uint32_t spcmd; /* 0x1e4 */
|
||||||
|
uint32_t actim1; /* 0x1e8 */
|
||||||
|
uint32_t perfctl0; /* 0x1ec */
|
||||||
|
uint32_t ac_derating; /* 0x1f0 */
|
||||||
|
uint32_t rrrate_ctl; /* 0x1f4 */
|
||||||
|
uint32_t ac_time_05t; /* 0x1f8 */
|
||||||
|
uint32_t mrr_ctl; /* 0x1fc */
|
||||||
|
uint32_t rsvd_ao16[4]; /* 0x200 */
|
||||||
|
uint32_t dqidly[9]; /* 0x210 */
|
||||||
|
uint32_t rsvd_ao17[115]; /* 0x234 */
|
||||||
|
uint32_t selph1; /* 0x400 */
|
||||||
|
uint32_t selph2; /* 0x404 */
|
||||||
|
uint32_t selph3; /* 0x408 */
|
||||||
|
uint32_t selph4; /* 0x40c */
|
||||||
|
uint32_t selph5; /* 0x410 */
|
||||||
|
uint32_t selph6; /* 0x414 */
|
||||||
|
uint32_t selph6_1; /* 0x418 */
|
||||||
|
uint32_t selph7; /* 0x41c */
|
||||||
|
uint32_t selph8; /* 0x420 */
|
||||||
|
uint32_t selph9; /* 0x424 */
|
||||||
|
uint32_t selph10; /* 0x428 */
|
||||||
|
uint32_t selph11; /* 0x42c */
|
||||||
|
};
|
||||||
|
|
||||||
|
check_member(dramc_ao_regs, selph11, 0x42c);
|
||||||
|
|
||||||
|
struct dramc_nao_regs {
|
||||||
|
uint32_t rsvd_nao1[11]; /* 0x0 */
|
||||||
|
uint32_t test_mode; /* 0x2c */
|
||||||
|
uint32_t rsvd_nao2[3]; /* 0x30 */
|
||||||
|
uint32_t test2_1; /* 0x3c */
|
||||||
|
uint32_t test2_2; /* 0x40 */
|
||||||
|
uint32_t rsvd_nao3[48]; /* 0x44 */
|
||||||
|
uint32_t lbwdat0; /* 0x104 */
|
||||||
|
uint32_t lbwdat1; /* 0x108 */
|
||||||
|
uint32_t lbwdat2; /* 0x10c */
|
||||||
|
uint32_t rsvd_nao4[1]; /* 0x110 */
|
||||||
|
uint32_t ckphdet; /* 0x114 */
|
||||||
|
uint32_t rsvd_nao5[48]; /* 0x118 */
|
||||||
|
uint32_t dmmonitor; /* 0x1d8 */
|
||||||
|
uint32_t rsvd_nao6[41]; /* 0x1dc */
|
||||||
|
uint32_t r2r_page_hit_counter; /* 0x280 */
|
||||||
|
uint32_t r2r_page_miss_counter; /* 0x284 */
|
||||||
|
uint32_t r2r_interbank_counter; /* 0x288 */
|
||||||
|
uint32_t r2w_page_hit_counter; /* 0x28c */
|
||||||
|
uint32_t r2w_page_miss_counter; /* 0x290 */
|
||||||
|
uint32_t r2w_interbank_counter; /* 0x294 */
|
||||||
|
uint32_t w2r_page_hit_counter; /* 0x298 */
|
||||||
|
uint32_t w2r_page_miss_counter; /* 0x29c */
|
||||||
|
uint32_t w2r_page_interbank_counter; /* 0x2a0 */
|
||||||
|
uint32_t w2w_page_hit_counter; /* 0x2a4 */
|
||||||
|
uint32_t w2w_page_miss_counter; /* 0x2a8 */
|
||||||
|
uint32_t w2w_page_interbank_counter; /* 0x2ac */
|
||||||
|
uint32_t dramc_idle_counter; /* 0x2b0 */
|
||||||
|
uint32_t freerun_26m_counter; /* 0x2b4 */
|
||||||
|
uint32_t refresh_pop_counter; /* 0x2b8 */
|
||||||
|
uint32_t jmeter_st; /* 0x2bc */
|
||||||
|
uint32_t dq_cal_max[8]; /* 0x2c0 */
|
||||||
|
uint32_t dqs_cal_min[8]; /* 0x2e0 */
|
||||||
|
uint32_t dqs_cal_max[8]; /* 0x300 */
|
||||||
|
uint32_t rsvd_nao7[4]; /* 0x320 */
|
||||||
|
uint32_t read_bytes_counter; /* 0x330 */
|
||||||
|
uint32_t write_bytes_counter; /* 0x334 */
|
||||||
|
uint32_t rsvd_nao8[6]; /* 0x338 */
|
||||||
|
uint32_t dqical[4]; /* 0x350 */
|
||||||
|
uint32_t rsvd_nao9[4]; /* 0x360 */
|
||||||
|
uint32_t cmp_err; /* 0x370 */
|
||||||
|
uint32_t r0dqsiendly; /* 0x374 */
|
||||||
|
uint32_t r1dqsiendly; /* 0x378 */
|
||||||
|
uint32_t rsvd_nao10[9]; /* 0x37c */
|
||||||
|
uint32_t dqsdly0; /* 0x3a0 */
|
||||||
|
uint32_t rsvd_nao11[4]; /* 0x3a4 */
|
||||||
|
uint32_t mrrdata; /* 0x3b4 */
|
||||||
|
uint32_t spcmdresp; /* 0x3b8 */
|
||||||
|
uint32_t iorgcnt; /* 0x3bc */
|
||||||
|
uint32_t dqsgnwcnt[6]; /* 0x3c0 */
|
||||||
|
uint32_t rsvd_nao12[4]; /* 0x3d8 */
|
||||||
|
uint32_t ckphcnt; /* 0x3e8 */
|
||||||
|
uint32_t rsvd_nao13[4]; /* 0x3ec */
|
||||||
|
uint32_t testrpt; /* 0x3fc */
|
||||||
|
};
|
||||||
|
|
||||||
|
check_member(dramc_nao_regs, testrpt, 0x3fc);
|
||||||
|
|
||||||
|
struct dramc_ddrphy_regs {
|
||||||
|
uint32_t rsvd_phy1[3]; /* 0x0 */
|
||||||
|
uint32_t padctl1; /* 0xc */
|
||||||
|
uint32_t padctl2; /* 0x10 */
|
||||||
|
uint32_t padctl3; /* 0x14 */
|
||||||
|
uint32_t rsvd_phy2[25]; /* 0x18 */
|
||||||
|
uint32_t ddr2ctl; /* 0x7c */
|
||||||
|
uint32_t rsvd_phy3[3]; /* 0x80 */
|
||||||
|
uint32_t clk1delay; /* 0x8c */
|
||||||
|
uint32_t ioctl; /* 0x90 */
|
||||||
|
uint32_t rsvd_phy4[7]; /* 0x94 */
|
||||||
|
uint32_t iodrv4; /* 0xb0 */
|
||||||
|
uint32_t iodrv5; /* 0xb4 */
|
||||||
|
uint32_t iodrv6; /* 0xb8 */
|
||||||
|
uint32_t drvctl1; /* 0xbc */
|
||||||
|
uint32_t dllsel; /* 0xc0 */
|
||||||
|
uint32_t rsvd_phy5[2]; /* 0xc4 */
|
||||||
|
uint32_t tdsel[3]; /* 0xcc */
|
||||||
|
uint32_t mckdly; /* 0xd8 */
|
||||||
|
uint32_t dqsctl0; /* 0xdc */
|
||||||
|
uint32_t dqsctl1; /* 0xe0 */
|
||||||
|
uint32_t dqsctl4; /* 0xe4 */
|
||||||
|
uint32_t dqsctl5; /* 0xe8 */
|
||||||
|
uint32_t dqsctl6; /* 0xec */
|
||||||
|
uint32_t phyctl1; /* 0xf0 */
|
||||||
|
uint32_t gddr3ctl1; /* 0xf4 */
|
||||||
|
uint32_t rsvd_phy6[1]; /* 0xf8 */
|
||||||
|
uint32_t misctl0; /* 0xfc */
|
||||||
|
uint32_t ocdk; /* 0x100 */
|
||||||
|
uint32_t rsvd_phy7[8]; /* 0x104 */
|
||||||
|
uint32_t dqsgctl; /* 0x124 */
|
||||||
|
uint32_t rsvd_phy8[6]; /* 0x128 */
|
||||||
|
uint32_t ddrphydqsgctl; /* 0x140 */
|
||||||
|
uint32_t dqsgct2; /* 0x144 */
|
||||||
|
uint32_t phyclkduty; /* 0x148 */
|
||||||
|
uint32_t rsvd_phy9[3]; /* 0x14c */
|
||||||
|
uint32_t dqsisel; /* 0x158 */
|
||||||
|
uint32_t dqmdqs_sel; /* 0x15c */
|
||||||
|
uint32_t rsvd_phy10[10]; /* 0x160 */
|
||||||
|
uint32_t jmeterpop1; /* 0x188 */
|
||||||
|
uint32_t jmeterpop2; /* 0x18c */
|
||||||
|
uint32_t jmeterpop3; /* 0x190 */
|
||||||
|
uint32_t jmeterpop4; /* 0x194 */
|
||||||
|
uint32_t rsvd_phy11[4]; /* 0x198 */
|
||||||
|
uint32_t cmddly[6]; /* 0x1a8 */
|
||||||
|
uint32_t dqscal0; /* 0x1c0 */
|
||||||
|
uint32_t rsvd_phy12[2]; /* 0x1c4 */
|
||||||
|
uint32_t jmeter[3]; /* 0x1cc */
|
||||||
|
uint32_t rsvd_phy13[2]; /* 0x1d8 */
|
||||||
|
uint32_t lpddr2_3; /* 0x1e0 */
|
||||||
|
uint32_t spcmd; /* 0x1e4 */
|
||||||
|
uint32_t rsvd_phy14[6]; /* 0x1e8 */
|
||||||
|
uint32_t dqodly[4]; /* 0x200 */
|
||||||
|
uint32_t rsvd_phy15[11]; /* 0x210 */
|
||||||
|
uint32_t lpddr2_4; /* 0x23c */
|
||||||
|
uint32_t rsvd_phy16[56]; /* 0x240 */
|
||||||
|
uint32_t jmeter_pll_st[3]; /* 0x320 */
|
||||||
|
uint32_t jmeter_done_st; /* 0x32c */
|
||||||
|
uint32_t rsvd_phy17[2]; /* 0x330 */
|
||||||
|
uint32_t jmeter_pll1_st; /* 0x338 */
|
||||||
|
uint32_t jmeter_pop_pll2_st; /* 0x33c */
|
||||||
|
uint32_t jmeter_pop_pll3_st; /* 0x340 */
|
||||||
|
uint32_t jmeter_pop_pll4_st; /* 0x344 */
|
||||||
|
uint32_t jmeter_pop_pll1_st; /* 0x348 */
|
||||||
|
uint32_t rsvd_phy18[13]; /* 0x34c */
|
||||||
|
uint32_t dq_o1; /* 0x380 */
|
||||||
|
uint32_t rsvd_phy19[2]; /* 0x384 */
|
||||||
|
uint32_t stben[4]; /* 0x38c */
|
||||||
|
uint32_t rsvd_phy20[16]; /* 0x39c */
|
||||||
|
uint32_t dllcnt0; /* 0x3dc */
|
||||||
|
uint32_t pllautok; /* 0x3e0 */
|
||||||
|
uint32_t poppllautok; /* 0x3e4 */
|
||||||
|
uint32_t rsvd_phy21[18]; /* 0x3e8 */
|
||||||
|
uint32_t selph12; /* 0x430 */
|
||||||
|
uint32_t selph13; /* 0x434 */
|
||||||
|
uint32_t selph14; /* 0x438 */
|
||||||
|
uint32_t selph15; /* 0x43c */
|
||||||
|
uint32_t selph16; /* 0x440 */
|
||||||
|
uint32_t selph17; /* 0x444 */
|
||||||
|
uint32_t selph18; /* 0x448 */
|
||||||
|
uint32_t selph19; /* 0x44c */
|
||||||
|
uint32_t selph20; /* 0x450 */
|
||||||
|
uint32_t rsvd_phy22[91]; /* 0x454 */
|
||||||
|
uint32_t peri[4]; /* 0x5c0 */
|
||||||
|
uint32_t rsvd_phy23[12]; /* 0x5d0 */
|
||||||
|
uint32_t mempll[15]; /* 0x600 */
|
||||||
|
uint32_t ddrphy_cg_ctrl; /* 0x63c */
|
||||||
|
uint32_t mempll_divider; /* 0x640 */
|
||||||
|
uint32_t vrefctl0; /* 0x644 */
|
||||||
|
uint32_t rsvd_phy24[18]; /* 0x648 */
|
||||||
|
uint32_t mempll05_divider; /* 0x690 */
|
||||||
|
};
|
||||||
|
|
||||||
|
check_member(dramc_ddrphy_regs, mempll05_divider, 0x690);
|
||||||
|
|
||||||
|
struct emi_regs {
|
||||||
|
uint32_t emi_cona; /* 0x0 */
|
||||||
|
uint32_t rsvd_emi1; /* 0x4 */
|
||||||
|
uint32_t emi_conb; /* 0x08 */
|
||||||
|
uint32_t rsvd_emi2; /* 0x0c */
|
||||||
|
uint32_t emi_conc; /* 0x10 */
|
||||||
|
uint32_t rsvd_emi3; /* 0x14 */
|
||||||
|
uint32_t emi_cond; /* 0x18 */
|
||||||
|
uint32_t rsvd_emi4; /* 0x1c */
|
||||||
|
uint32_t emi_cone; /* 0x20 */
|
||||||
|
uint32_t rsvd_emi5; /* 0x24 */
|
||||||
|
uint32_t emi_conf; /* 0x28 */
|
||||||
|
uint32_t rsvd_emi6; /* 0x2c */
|
||||||
|
uint32_t emi_cong; /* 0x30 */
|
||||||
|
uint32_t rsvd_emi7; /* 0x34 */
|
||||||
|
uint32_t emi_conh; /* 0x38 */
|
||||||
|
uint32_t rsvd_emi8[9]; /* 0x3c */
|
||||||
|
uint32_t emi_conm; /* 0x60 */
|
||||||
|
uint32_t rsvd_emi9[5]; /* 0x64 */
|
||||||
|
uint32_t emi_mdct; /* 0x78 */
|
||||||
|
uint32_t rsvd_emi10[21]; /* 0x7c */
|
||||||
|
uint32_t emi_test0; /* 0xd0 */
|
||||||
|
uint32_t rsvd_emi11; /* 0xd4 */
|
||||||
|
uint32_t emi_test1; /* 0xd8 */
|
||||||
|
uint32_t rsvd_emi12; /* 0xdc */
|
||||||
|
uint32_t emi_testa; /* 0xe0 */
|
||||||
|
uint32_t rsvd_emi13; /* 0xe4 */
|
||||||
|
uint32_t emi_testb; /* 0xe8 */
|
||||||
|
uint32_t rsvd_emi14; /* 0xec */
|
||||||
|
uint32_t emi_testc; /* 0xf0 */
|
||||||
|
uint32_t rsvd_emi15; /* 0xf4 */
|
||||||
|
uint32_t emi_testd; /* 0xf8 */
|
||||||
|
uint32_t rsvd_emi16; /* 0xfc */
|
||||||
|
uint32_t emi_arba; /* 0x100 */
|
||||||
|
uint32_t rsvd_emi17[3]; /* 0x104 */
|
||||||
|
uint32_t emi_arbc; /* 0x110 */
|
||||||
|
uint32_t rsvd_emi18; /* 0x114 */
|
||||||
|
uint32_t emi_arbd; /* 0x118 */
|
||||||
|
uint32_t rsvd_emi19; /* 0x11c */
|
||||||
|
uint32_t emi_arbe; /* 0x120 */
|
||||||
|
uint32_t rsvd_emi20; /* 0x124 */
|
||||||
|
uint32_t emi_arbf; /* 0x128 */
|
||||||
|
uint32_t rsvd_emi21; /* 0x12c */
|
||||||
|
uint32_t emi_arbg; /* 0x130 */
|
||||||
|
uint32_t rsvd_emi22; /* 0x134 */
|
||||||
|
uint32_t emi_arbh; /* 0x138 */
|
||||||
|
uint32_t rsvd_emi23; /* 0x13c */
|
||||||
|
uint32_t emi_arbi; /* 0x140 */
|
||||||
|
uint32_t emi_arbi_2nd; /* 0x144 */
|
||||||
|
uint32_t emi_arbj; /* 0x148 */
|
||||||
|
uint32_t emi_arbj_2nd; /* 0x14c */
|
||||||
|
uint32_t emi_arbk; /* 0x150 */
|
||||||
|
uint32_t emi_arbk_2nd; /* 0x154 */
|
||||||
|
uint32_t emi_slct; /* 0x158 */
|
||||||
|
uint32_t rsvd_emi24; /* 0x15C */
|
||||||
|
uint32_t emi_mpua; /* 0x160 */
|
||||||
|
uint32_t rsvd_emi25; /* 0x164 */
|
||||||
|
uint32_t emi_mpub; /* 0x168 */
|
||||||
|
uint32_t rsvd_emi26; /* 0x16c */
|
||||||
|
uint32_t emi_mpuc; /* 0x170 */
|
||||||
|
uint32_t rsvd_emi27; /* 0x174 */
|
||||||
|
uint32_t emi_mpud; /* 0x178 */
|
||||||
|
uint32_t rsvd_emi28; /* 0x17C */
|
||||||
|
uint32_t emi_mpue; /* 0x180 */
|
||||||
|
uint32_t rsvd_emi29; /* 0x184 */
|
||||||
|
uint32_t emi_mpuf; /* 0x188 */
|
||||||
|
uint32_t rsvd_emi30; /* 0x18C */
|
||||||
|
uint32_t emi_mpug; /* 0x190 */
|
||||||
|
uint32_t rsvd_emi31; /* 0x194 */
|
||||||
|
uint32_t emi_mpuh; /* 0x198 */
|
||||||
|
uint32_t rsvd_emi32; /* 0x19C */
|
||||||
|
uint32_t emi_mpui; /* 0x1A0 */
|
||||||
|
uint32_t rsvd_emi33; /* 0x1A4 */
|
||||||
|
uint32_t emi_mpuj; /* 0x1A8 */
|
||||||
|
uint32_t rsvd_emi34; /* 0x1AC */
|
||||||
|
uint32_t emi_mpuk; /* 0x1B0 */
|
||||||
|
uint32_t rsvd_emi35; /* 0x1B4 */
|
||||||
|
uint32_t emi_mpul; /* 0x1B8 */
|
||||||
|
uint32_t rsvd_emi36; /* 0x1BC */
|
||||||
|
uint32_t emi_mpum; /* 0x1C0 */
|
||||||
|
uint32_t rsvd_emi37; /* 0x1C4 */
|
||||||
|
uint32_t emi_mpun; /* 0x1C8 */
|
||||||
|
uint32_t rsvd_emi38; /* 0x1CC */
|
||||||
|
uint32_t emi_mpuo; /* 0x1D0 */
|
||||||
|
uint32_t rsvd_emi39; /* 0x1D4 */
|
||||||
|
uint32_t emi_mpup; /* 0x1D8 */
|
||||||
|
uint32_t rsvd_emi40; /* 0x1DC */
|
||||||
|
uint32_t emi_mpuq; /* 0x1E0 */
|
||||||
|
uint32_t rsvd_emi41; /* 0x1E4 */
|
||||||
|
uint32_t emi_mpur; /* 0x1E8 */
|
||||||
|
uint32_t rsvd_emi42; /* 0x1EC */
|
||||||
|
uint32_t emi_mpus; /* 0x1F0 */
|
||||||
|
uint32_t rsvd_emi43; /* 0x1F4 */
|
||||||
|
uint32_t emi_mput; /* 0x1F8 */
|
||||||
|
uint32_t rsvd_emi44; /* 0x1FC */
|
||||||
|
uint32_t emi_mpuu; /* 0x200 */
|
||||||
|
uint32_t rsvd_emi45[7]; /* 0x204 */
|
||||||
|
uint32_t emi_mpuy; /* 0x220 */
|
||||||
|
uint32_t rsvd_emi46[119]; /* 0x224 */
|
||||||
|
uint32_t emi_bmen; /* 0x400 */
|
||||||
|
};
|
||||||
|
|
||||||
|
check_member(emi_regs, emi_bmen, 0x400);
|
||||||
|
|
||||||
|
extern struct dramc_ao_regs *ao_regs;
|
||||||
|
extern struct dramc_nao_regs *nao_regs;
|
||||||
|
extern struct dramc_ddrphy_regs *ddrphy_regs;
|
||||||
|
|
||||||
|
struct dramc_channel {
|
||||||
|
struct dramc_ao_regs *ao_regs;
|
||||||
|
struct dramc_nao_regs *nao_regs;
|
||||||
|
struct dramc_ddrphy_regs *ddrphy_regs;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dramc_channel const ch[2] = {
|
||||||
|
{(void *)CHA_DRAMCAO_BASE, (void *)CHA_DRAMCNAO_BASE, (void *)CHA_DDRPHY_BASE},
|
||||||
|
{(void *)CHB_DRAMCAO_BASE, (void *)CHB_DRAMCNAO_BASE, (void *)CHB_DDRPHY_BASE}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _DRAMC_REGISTER_H_ */
|
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SOC_MEDIATEK_MT8173_EMI_H
|
||||||
|
#define SOC_MEDIATEK_MT8173_EMI_H
|
||||||
|
|
||||||
|
#include <soc/dramc_common.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* DDR type */
|
||||||
|
enum ram_type {
|
||||||
|
TYPE_INVALID,
|
||||||
|
TYPE_DDR1,
|
||||||
|
TYPE_LPDDR2,
|
||||||
|
TYPE_LPDDR3,
|
||||||
|
TYPE_PCDDR3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/*
|
||||||
|
* Vmem voltage adjustment:
|
||||||
|
* 1) HV: high voltage
|
||||||
|
* 2) NV: normal voltage
|
||||||
|
* 3) LV: low voltage
|
||||||
|
*/
|
||||||
|
Vmem_HV_LPDDR3 = 0x50, /* 1.300V */
|
||||||
|
Vmem_NV_LPDDR3 = 0x44, /* 1.225V */
|
||||||
|
Vmem_LV_LPDDR3 = 0x36 /* 1.138V */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/*
|
||||||
|
* Vcore voltage adjustment:
|
||||||
|
* 1) HHV: extra high voltage
|
||||||
|
* 2) HV: high voltage
|
||||||
|
* 3) NV: normal voltage
|
||||||
|
* 4) LV: low voltage
|
||||||
|
* 5) LLV: extra low voltage
|
||||||
|
*/
|
||||||
|
Vcore_HHV_LPPDR3 = 0x60, /* 1.300V */
|
||||||
|
Vcore_HV_LPPDR3 = 0x48, /* 1.150V */
|
||||||
|
Vcore_NV_LPPDR3 = 0x44, /* 1.125V */
|
||||||
|
Vcore_LV_LPPDR3 = 0x34, /* 1.025V */
|
||||||
|
Vcore_LLV_LPPDR3 = 0x25 /* 0.931V */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mt8173_calib_params {
|
||||||
|
u8 impedance_drvp;
|
||||||
|
u8 impedance_drvn;
|
||||||
|
u8 datlat_ucfirst;
|
||||||
|
s8 ca_train[CHANNEL_NUM][CATRAINING_NUM];
|
||||||
|
s8 ca_train_center[CHANNEL_NUM];
|
||||||
|
s8 wr_level[CHANNEL_NUM][DQS_NUMBER];
|
||||||
|
u8 gating_win[CHANNEL_NUM][DUAL_RANKS][GW_PARAM_NUM];
|
||||||
|
u32 rx_dqs_dly[CHANNEL_NUM];
|
||||||
|
u32 rx_dq_dly[CHANNEL_NUM][DQS_BIT_NUMBER];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mt8173_timing_params {
|
||||||
|
u32 actim;
|
||||||
|
u32 actim1;
|
||||||
|
u32 actim05t;
|
||||||
|
u32 conf1;
|
||||||
|
u32 conf2;
|
||||||
|
u32 ddr2ctl;
|
||||||
|
u32 gddr3ctl1;
|
||||||
|
u32 misctl0;
|
||||||
|
u32 pd_ctrl;
|
||||||
|
u32 rkcfg;
|
||||||
|
u32 test2_4;
|
||||||
|
u32 test2_3;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mt8173_emi_params {
|
||||||
|
u32 cona;
|
||||||
|
u32 conb;
|
||||||
|
u32 conc;
|
||||||
|
u32 cond;
|
||||||
|
u32 cone;
|
||||||
|
u32 conf;
|
||||||
|
u32 cong;
|
||||||
|
u32 conh;
|
||||||
|
u32 conm_1;
|
||||||
|
u32 conm_2;
|
||||||
|
u32 mdct_1;
|
||||||
|
u32 mdct_2;
|
||||||
|
u32 test0;
|
||||||
|
u32 test1;
|
||||||
|
u32 testb;
|
||||||
|
u32 testc;
|
||||||
|
u32 testd;
|
||||||
|
u32 arba;
|
||||||
|
u32 arbc;
|
||||||
|
u32 arbd;
|
||||||
|
u32 arbe;
|
||||||
|
u32 arbf;
|
||||||
|
u32 arbg;
|
||||||
|
u32 arbi;
|
||||||
|
u32 arbj;
|
||||||
|
u32 arbk;
|
||||||
|
u32 slct_1;
|
||||||
|
u32 slct_2;
|
||||||
|
u32 bmen;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mt8173_mrs_params {
|
||||||
|
u32 mrs_1;
|
||||||
|
u32 mrs_2;
|
||||||
|
u32 mrs_3;
|
||||||
|
u32 mrs_10;
|
||||||
|
u32 mrs_11;
|
||||||
|
u32 mrs_63;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mt8173_sdram_params {
|
||||||
|
struct mt8173_calib_params calib_params;
|
||||||
|
struct mt8173_timing_params ac_timing;
|
||||||
|
struct mt8173_emi_params emi_set;
|
||||||
|
struct mt8173_mrs_params mrs_set;
|
||||||
|
enum ram_type type;
|
||||||
|
unsigned int dram_freq;
|
||||||
|
};
|
||||||
|
|
||||||
|
void mt_set_emi(const struct mt8173_sdram_params *sdram_params);
|
||||||
|
void mt_mem_init(const struct mt8173_sdram_params *sdram_params);
|
||||||
|
const struct mt8173_sdram_params *get_sdram_config(void);
|
||||||
|
|
||||||
|
#endif
|
|
@ -16,6 +16,7 @@
|
||||||
#ifndef SOC_MEDIATEK_MT8173_PLL_H
|
#ifndef SOC_MEDIATEK_MT8173_PLL_H
|
||||||
#define SOC_MEDIATEK_MT8173_PLL_H
|
#define SOC_MEDIATEK_MT8173_PLL_H
|
||||||
|
|
||||||
|
#include <soc/emi.h>
|
||||||
#include <soc/addressmap.h>
|
#include <soc/addressmap.h>
|
||||||
|
|
||||||
struct mt8173_topckgen_regs {
|
struct mt8173_topckgen_regs {
|
||||||
|
@ -285,5 +286,9 @@ void mt_pll_post_init(void);
|
||||||
void mt_pll_init(void);
|
void mt_pll_init(void);
|
||||||
void mt_pll_set_aud_div(u32 rate);
|
void mt_pll_set_aud_div(u32 rate);
|
||||||
void mt_pll_enable_ssusb_clk(void);
|
void mt_pll_enable_ssusb_clk(void);
|
||||||
|
void mt_mem_pll_set_clk_cfg(void);
|
||||||
|
void mt_mem_pll_config_pre(const struct mt8173_sdram_params *sdram_params);
|
||||||
|
void mt_mem_pll_config_post(void);
|
||||||
|
void mt_mem_pll_mux(void);
|
||||||
|
|
||||||
#endif /* SOC_MEDIATEK_MT8173_PLL_H */
|
#endif /* SOC_MEDIATEK_MT8173_PLL_H */
|
||||||
|
|
|
@ -0,0 +1,357 @@
|
||||||
|
/*
|
||||||
|
* 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 <console/console.h>
|
||||||
|
#include <soc/addressmap.h>
|
||||||
|
#include <soc/dramc_register.h>
|
||||||
|
#include <soc/dramc_pi_api.h>
|
||||||
|
#include <soc/emi.h>
|
||||||
|
#include <soc/pll.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* test patterns */
|
||||||
|
PATTERN0 = 0x00000000,
|
||||||
|
PATTERN1 = 0x5A5A5A5A,
|
||||||
|
PATTERN2 = 0xA5A5A5A5,
|
||||||
|
PATTERN3 = 0xA5A5A500,
|
||||||
|
PATTERN4 = 0xA500A500,
|
||||||
|
PATTERN5 = 0xA5000000,
|
||||||
|
PATTERN6 = 0xFFFF0000,
|
||||||
|
PATTERN7 = 0x0000FFFF,
|
||||||
|
PATTERN8 = 0x00000012,
|
||||||
|
PATTERN9 = 0x00000034,
|
||||||
|
PATTERNA = 0x00000056,
|
||||||
|
PATTERNB = 0x00000078,
|
||||||
|
PATTERNC = 0x00001234,
|
||||||
|
PATTERND = 0x00005678,
|
||||||
|
PATTERNE = 0x12345678,
|
||||||
|
PATTERNF = 0xFFFFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
static int complex_mem_test(unsigned int start, unsigned int len)
|
||||||
|
{
|
||||||
|
unsigned char *mem8_base = (unsigned char *)(uintptr_t)start;
|
||||||
|
unsigned short *mem16_base = (unsigned short *)(uintptr_t)start;
|
||||||
|
unsigned int *mem32_base = (unsigned int *)(uintptr_t)start;
|
||||||
|
unsigned int *mem_base = (unsigned int *)(uintptr_t)start;
|
||||||
|
unsigned char pattern8;
|
||||||
|
unsigned short pattern16;
|
||||||
|
unsigned int i, j, size, pattern32;
|
||||||
|
unsigned int value;
|
||||||
|
|
||||||
|
size = len >> 2;
|
||||||
|
|
||||||
|
/* verify the tied bits (tied high) */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
mem32_base[i] = PATTERN0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (mem32_base[i] != PATTERN0) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
mem32_base[i] = PATTERNF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify the tied bits (tied low) */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (mem32_base[i] != PATTERNF) {
|
||||||
|
return -2;
|
||||||
|
} else
|
||||||
|
mem32_base[i] = PATTERN0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify pattern 1 (0x00~0xff) */
|
||||||
|
pattern8 = PATTERN0;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
mem8_base[i] = pattern8++;
|
||||||
|
pattern8 = PATTERN0;
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (mem8_base[i] != pattern8++) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify pattern 2 (0x00~0xff) */
|
||||||
|
pattern8 = PATTERN0;
|
||||||
|
for (i = j = 0; i < len; i += 2, j++) {
|
||||||
|
if (mem8_base[i] == pattern8)
|
||||||
|
mem16_base[j] = pattern8;
|
||||||
|
if (mem16_base[j] != pattern8) {
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
pattern8 += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify pattern 3 (0x00~0xffff) */
|
||||||
|
pattern16 = PATTERN0;
|
||||||
|
for (i = 0; i < (len >> 1); i++)
|
||||||
|
mem16_base[i] = pattern16++;
|
||||||
|
pattern16 = PATTERN0;
|
||||||
|
for (i = 0; i < (len >> 1); i++) {
|
||||||
|
if (mem16_base[i] != pattern16++) {
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify pattern 4 (0x00~0xffffffff) */
|
||||||
|
pattern32 = PATTERN0;
|
||||||
|
for (i = 0; i < (len >> 2); i++)
|
||||||
|
mem32_base[i] = pattern32++;
|
||||||
|
pattern32 = PATTERN0;
|
||||||
|
for (i = 0; i < (len >> 2); i++) {
|
||||||
|
if (mem32_base[i] != pattern32++) {
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pattern 5: filling memory range with 0x12345678 */
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
mem32_base[i] = PATTERNE;
|
||||||
|
|
||||||
|
/* read check then fill memory with a5a5a5a5 pattern */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (mem32_base[i] != PATTERNE) {
|
||||||
|
return -7;
|
||||||
|
} else {
|
||||||
|
mem32_base[i] = PATTERN2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read check then fill memory with 00 byte pattern at offset 0h */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (mem32_base[i] != PATTERN2) {
|
||||||
|
return -8;
|
||||||
|
} else {
|
||||||
|
mem8_base[i * 4] = PATTERN0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read check then fill memory with 00 byte pattern at offset 2h */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (mem32_base[i] != PATTERN3) {
|
||||||
|
return -9;
|
||||||
|
} else {
|
||||||
|
mem8_base[i * 4 + 2] = PATTERN0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read check then fill memory with 00 byte pattern at offset 1h */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (mem32_base[i] != PATTERN4) {
|
||||||
|
return -10;
|
||||||
|
} else {
|
||||||
|
mem8_base[i * 4 + 1] = PATTERN0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read check then fill memory with 00 byte pattern at offset 3h */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (mem32_base[i] != PATTERN5) {
|
||||||
|
return -11;
|
||||||
|
} else {
|
||||||
|
mem8_base[i * 4 + 3] = PATTERN0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read check then fill memory with ffff word pattern at offset 1h */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (mem32_base[i] != PATTERN0) {
|
||||||
|
return -12;
|
||||||
|
} else {
|
||||||
|
mem16_base[i * 2 + 1] = PATTERN7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read check then fill memory with ffff word pattern at offset 0h */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (mem32_base[i] != PATTERN6) {
|
||||||
|
return -13;
|
||||||
|
} else {
|
||||||
|
mem16_base[i * 2] = PATTERN7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read check */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (mem32_base[i] != PATTERNF) {
|
||||||
|
return -14;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stage 1 => write 0 */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
mem_base[i] = PATTERN1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stage 2 => read 0, write 0xf */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
value = mem_base[i];
|
||||||
|
|
||||||
|
if (value != PATTERN1) {
|
||||||
|
return -15;
|
||||||
|
}
|
||||||
|
mem_base[i] = PATTERN2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stage 3 => read 0xf, write 0 */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
value = mem_base[i];
|
||||||
|
if (value != PATTERN2) {
|
||||||
|
return -16;
|
||||||
|
}
|
||||||
|
mem_base[i] = PATTERN1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stage 4 => read 0, write 0xf */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
value = mem_base[i];
|
||||||
|
if (value != PATTERN1) {
|
||||||
|
return -17;
|
||||||
|
}
|
||||||
|
mem_base[i] = PATTERN2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stage 5 => read 0xf, write 0 */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
value = mem_base[i];
|
||||||
|
if (value != PATTERN2) {
|
||||||
|
return -18;
|
||||||
|
}
|
||||||
|
mem_base[i] = PATTERN1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stage 6 => read 0 */
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
value = mem_base[i];
|
||||||
|
if (value != PATTERN1) {
|
||||||
|
return -19;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 1/2/4-byte combination test */
|
||||||
|
i = (unsigned int)(uintptr_t)mem_base;
|
||||||
|
|
||||||
|
while (i < (unsigned int)(uintptr_t)mem_base + (size << 2)) {
|
||||||
|
*((unsigned char *)(uintptr_t)i) = PATTERNB;
|
||||||
|
i += 1;
|
||||||
|
*((unsigned char *)(uintptr_t)i) = PATTERNA;
|
||||||
|
i += 1;
|
||||||
|
*((unsigned short *)(uintptr_t)i) = PATTERNC;
|
||||||
|
i += 2;
|
||||||
|
*((unsigned int *)(uintptr_t)i) = PATTERNE;
|
||||||
|
i += 4;
|
||||||
|
*((unsigned short *)(uintptr_t)i) = PATTERND;
|
||||||
|
i += 2;
|
||||||
|
*((unsigned char *)(uintptr_t)i) = PATTERN9;
|
||||||
|
i += 1;
|
||||||
|
*((unsigned char *)(uintptr_t)i) = PATTERN8;
|
||||||
|
i += 1;
|
||||||
|
*((unsigned int *)(uintptr_t)i) = PATTERNE;
|
||||||
|
i += 4;
|
||||||
|
*((unsigned char *)(uintptr_t)i) = PATTERNB;
|
||||||
|
i += 1;
|
||||||
|
*((unsigned char *)(uintptr_t)i) = PATTERNA;
|
||||||
|
i += 1;
|
||||||
|
*((unsigned short *)(uintptr_t)i) = PATTERNC;
|
||||||
|
i += 2;
|
||||||
|
*((unsigned int *)(uintptr_t)i) = PATTERNE;
|
||||||
|
i += 4;
|
||||||
|
*((unsigned short *)(uintptr_t)i) = PATTERND;
|
||||||
|
i += 2;
|
||||||
|
*((unsigned char *)(uintptr_t)i) = PATTERN9;
|
||||||
|
i += 1;
|
||||||
|
*((unsigned char *)(uintptr_t)i) = PATTERN8;
|
||||||
|
i += 1;
|
||||||
|
*((unsigned int *)(uintptr_t)i) = PATTERNE;
|
||||||
|
i += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
value = mem_base[i];
|
||||||
|
if (value != PATTERNE) {
|
||||||
|
return -20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify pattern 1 (0x00~0xff) */
|
||||||
|
pattern8 = PATTERN0;
|
||||||
|
mem8_base[0] = pattern8;
|
||||||
|
for (i = 0; i < size * 4; i++) {
|
||||||
|
unsigned char waddr8, raddr8;
|
||||||
|
|
||||||
|
waddr8 = i + 1;
|
||||||
|
raddr8 = i;
|
||||||
|
if (i < size * 4 - 1)
|
||||||
|
mem8_base[waddr8] = pattern8 + 1;
|
||||||
|
if (mem8_base[raddr8] != pattern8) {
|
||||||
|
return -21;
|
||||||
|
}
|
||||||
|
pattern8++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify pattern 2 (0x00~0xffff) */
|
||||||
|
pattern16 = PATTERN0;
|
||||||
|
mem16_base[0] = pattern16;
|
||||||
|
for (i = 0; i < size * 2; i++) {
|
||||||
|
if (i < size * 2 - 1)
|
||||||
|
mem16_base[i + 1] = pattern16 + 1;
|
||||||
|
if (mem16_base[i] != pattern16) {
|
||||||
|
return -22;
|
||||||
|
}
|
||||||
|
pattern16++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify pattern 3 (0x00~0xffffffff) */
|
||||||
|
pattern32 = PATTERN0;
|
||||||
|
mem32_base[0] = pattern32;
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (i < size - 1)
|
||||||
|
mem32_base[i + 1] = pattern32 + 1;
|
||||||
|
if (mem32_base[i] != pattern32) {
|
||||||
|
return -23;
|
||||||
|
}
|
||||||
|
pattern32++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mt_mem_init(const struct mt8173_sdram_params *sdram_params)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
/* init mempll */
|
||||||
|
mem_pll_init(sdram_params);
|
||||||
|
|
||||||
|
/* memory calibration */
|
||||||
|
mt_set_emi(sdram_params);
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_MEMORY_TEST)) {
|
||||||
|
/* do memory test:
|
||||||
|
* set memory scan range 0x2000
|
||||||
|
* larger test length, longer system boot up time
|
||||||
|
*/
|
||||||
|
i = complex_mem_test(DDR_BASE, 0x2000);
|
||||||
|
|
||||||
|
printk(BIOS_DEBUG, "[MEM] complex R/W mem test %s : %d\n",
|
||||||
|
(i == 0) ? "pass" : "fail", i);
|
||||||
|
|
||||||
|
ASSERT(i == 0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -505,3 +505,29 @@ void mt_pll_set_aud_div(u32 rate)
|
||||||
7 << 28);
|
7 << 28);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mt_mem_pll_config_pre(const struct mt8173_sdram_params *sdram_params)
|
||||||
|
{
|
||||||
|
u32 mpll_sdm_pcw_20_0 = 0xF13B1;
|
||||||
|
|
||||||
|
/* disable MPLL for adjusting memory clk frequency */
|
||||||
|
clrbits_le32(&mt8173_apmixed->mpll_con0, BIT(0));
|
||||||
|
/* MPLL configuration: mode selection */
|
||||||
|
setbits_le32(&mt8173_apmixed->mpll_con0, BIT(16));
|
||||||
|
clrbits_le32(&mt8173_apmixed->mpll_con0, 0x7 << 4);
|
||||||
|
clrbits_le32(&mt8173_apmixed->pll_test_con0, 1 << 31);
|
||||||
|
/* set RG_MPLL_SDM_PCW for feedback divide ratio */
|
||||||
|
clrsetbits_le32(&mt8173_apmixed->mpll_con1, 0x1fffff, mpll_sdm_pcw_20_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mt_mem_pll_config_post(void)
|
||||||
|
{
|
||||||
|
/* power up sequence starts: enable MPLL */
|
||||||
|
setbits_le32(&mt8173_apmixed->mpll_con0, BIT(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mt_mem_pll_mux(void)
|
||||||
|
{
|
||||||
|
/* CLK_CFG_0 */
|
||||||
|
mux_set_sel(&muxes[TOP_MEM_SEL], 1); /* 1: dmpll_ck */
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue