summaryrefslogtreecommitdiff
path: root/src/soc/mediatek/mt8183/dramc_pi_basic_api.c
diff options
context:
space:
mode:
authorHuayang Duan <huayang.duan@mediatek.com>2019-08-19 14:06:31 +0800
committerPatrick Georgi <pgeorgi@google.com>2019-09-20 07:22:10 +0000
commit7378015b740713f7ecd3ee53715154de1411541a (patch)
tree61e183eac302695b1462e0aa4fa6eb5705065236 /src/soc/mediatek/mt8183/dramc_pi_basic_api.c
parente68da64969fe3cd42b8b83e60d2337777f187620 (diff)
downloadcoreboot-7378015b740713f7ecd3ee53715154de1411541a.tar.xz
mediatek/mt8183: Implement the dramc init setting
This patch implements the dram init setting by replacing the hard-coded init sequence with a series of functions to support calibration for more frequencies. These functions are modified from MediaTek's internal DRAM full calibration source code. BUG=b:80501386 BRANCH=none TEST=1. Kukui boots correctly 2. Stress test (/usr/sbin/memtester 500M) passes on Kukui Change-Id: I756ad37e78cd1384ee0eb97e5e18c5461d73bc7b Signed-off-by: Huayang Duan <huayang.duan@mediatek.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/34988 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Diffstat (limited to 'src/soc/mediatek/mt8183/dramc_pi_basic_api.c')
-rw-r--r--src/soc/mediatek/mt8183/dramc_pi_basic_api.c120
1 files changed, 115 insertions, 5 deletions
diff --git a/src/soc/mediatek/mt8183/dramc_pi_basic_api.c b/src/soc/mediatek/mt8183/dramc_pi_basic_api.c
index cb462e987a..bf8bf0e15f 100644
--- a/src/soc/mediatek/mt8183/dramc_pi_basic_api.c
+++ b/src/soc/mediatek/mt8183/dramc_pi_basic_api.c
@@ -20,11 +20,21 @@
#include <soc/dramc_register.h>
#include <soc/dramc_pi_api.h>
+static u32 impedance[2][4];
+
+u8 get_freq_fsq(u8 freq)
+{
+ if (freq == LP4X_DDR1600 || freq == LP4X_DDR2400)
+ return FSP_0;
+ else
+ return FSP_1;
+}
+
static void dramc_sw_imp_cal_vref_sel(u8 term_option, u8 impcal_stage)
{
u8 vref_sel = 0;
- if (term_option == 1)
+ if (term_option == ODT_ON)
vref_sel = IMP_LP4X_TERM_VREF_SEL;
else {
switch (impcal_stage) {
@@ -43,14 +53,114 @@ static void dramc_sw_imp_cal_vref_sel(u8 term_option, u8 impcal_stage)
clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[11], 0x3f << 8, vref_sel << 8);
}
-void dramc_sw_impedance(const struct sdram_params *params)
+void dramc_sw_impedance_cal(const struct sdram_params *params, u8 term)
{
- u8 term = 0, ca_term = ODT_OFF, dq_term = ODT_ON;
+ u32 broadcast_bak, impcal_bak, imp_cal_result;
+ u32 DRVP_result = 0xff, ODTN_result = 0xff, DRVN_result = 0x9;
+
+ broadcast_bak = dramc_get_broadcast();
+ dramc_set_broadcast(DRAMC_BROADCAST_OFF);
+
+ clrbits_le32(&ch[0].phy.misc_spm_ctrl1, 0xf << 0);
+ write32(&ch[0].phy.misc_spm_ctrl2, 0x0);
+ write32(&ch[0].phy.misc_spm_ctrl0, 0x0);
+ clrbits_le32(&ch[0].ao.impcal, 0x1 << 31);
+
+ impcal_bak = read32(&ch[0].ao.impcal);
+ dramc_sw_imp_cal_vref_sel(term, IMPCAL_STAGE_DRVP);
+ clrbits_le32(&ch[0].phy.misc_imp_ctrl1, 0x1 << 6);
+ clrsetbits_le32(&ch[0].ao.impcal, 0x1 << 21, 0x3 << 24);
+ clrsetbits_le32(&ch[0].phy.misc_imp_ctrl0, 0x7 << 4, 0x3 << 4);
+ udelay(1);
+
+ dramc_show("K DRVP\n");
+ setbits_le32(&ch[0].ao.impcal, 0x1 << 23);
+ setbits_le32(&ch[0].ao.impcal, 0x1 << 22);
+ clrbits_le32(&ch[0].ao.impcal, 0x1 << 21);
+ clrbits_le32(&ch[0].ao.shu[0].impcal1, 0x1f << 4 | 0x1f << 11);
+ clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[11], 0xff << 0, 0x3);
+
+ for (u8 impx_drv = 0; impx_drv < 32; impx_drv++) {
+ impx_drv = (impx_drv == 16) ? 29 : impx_drv;
+
+ clrsetbits_le32(&ch[0].ao.shu[0].impcal1,
+ 0x1f << 4, impx_drv << 4);
+ udelay(1);
+ imp_cal_result = (read32(&ch[0].phy_nao.misc_phy_rgs_cmd) >>
+ 24) & 0x1;
+ dramc_show("1. OCD DRVP=%d CALOUT=%d\n",
+ impx_drv, imp_cal_result);
+
+ if (imp_cal_result == 1 && DRVP_result == 0xff) {
+ DRVP_result = impx_drv;
+ dramc_show("1. OCD DRVP calibration OK! DRVP=%d\n",
+ DRVP_result);
+ break;
+ }
+ }
+
+ dramc_show("K ODTN\n");
+ dramc_sw_imp_cal_vref_sel(term, IMPCAL_STAGE_DRVN);
+ clrbits_le32(&ch[0].ao.impcal, 0x1 << 22);
+ if (term == ODT_ON)
+ setbits_le32(&ch[0].ao.impcal, 0x1 << 21);
+ clrsetbits_le32(&ch[0].ao.shu[0].impcal1, 0x1f << 4 | 0x1f << 11,
+ DRVP_result << 4 | 0x1f << 11);
+ clrsetbits_le32(&ch[0].phy.shu[0].ca_cmd[11], 0xff << 0, 0x3);
+
+ for (u8 impx_drv = 0; impx_drv < 32; impx_drv++) {
+ impx_drv = (impx_drv == 16) ? 29 : impx_drv;
+
+ clrsetbits_le32(&ch[0].ao.shu[0].impcal1,
+ 0x1f << 11, impx_drv << 11);
+ udelay(1);
+ imp_cal_result = (read32(&ch[0].phy_nao.misc_phy_rgs_cmd) >>
+ 24) & 0x1;
+ dramc_show("3. OCD ODTN=%d CALOUT=%d\n",
+ impx_drv, imp_cal_result);
+
+ if (imp_cal_result == 0 && ODTN_result == 0xff) {
+ ODTN_result = impx_drv;
+ dramc_show("3. OCD ODTN calibration OK! ODTN=%d\n",
+ ODTN_result);
+ break;
+ }
+ }
+
+ write32(&ch[0].ao.impcal, impcal_bak);
+
+ dramc_show("term:%d, DRVP=%d, DRVN=%d, ODTN=%d\n",
+ term, DRVP_result, DRVN_result, ODTN_result);
+ if (term == ODT_OFF) {
+ impedance[term][0] = DRVP_result;
+ impedance[term][1] = ODTN_result;
+ impedance[term][2] = 0;
+ impedance[term][3] = 15;
+ } else {
+ impedance[term][0] = (DRVP_result <= 3) ?
+ (DRVP_result * 3) : DRVP_result;
+ impedance[term][1] = (DRVN_result <= 3) ?
+ (DRVN_result * 3) : DRVN_result;
+ impedance[term][2] = 0;
+ impedance[term][3] = (ODTN_result <= 3) ?
+ (ODTN_result * 3) : ODTN_result;
+ }
+ dramc_sw_imp_cal_vref_sel(term, IMPCAL_STAGE_TRACKING);
+
+ dramc_set_broadcast(broadcast_bak);
+}
+
+void dramc_sw_impedance_save_reg(u8 freq_group)
+{
+ u8 ca_term = ODT_OFF, dq_term = ODT_ON;
u32 sw_impedance[2][4] = {0};
- for (term = 0; term < 2; term++)
+ if (get_freq_fsq(freq_group) == FSP_0)
+ dq_term = ODT_OFF;
+
+ for (u8 term = 0; term < 2; term++)
for (u8 i = 0; i < 4; i++)
- sw_impedance[term][i] = params->impedance[term][i];
+ sw_impedance[term][i] = impedance[term][i];
sw_impedance[ODT_OFF][2] = sw_impedance[ODT_ON][2];
sw_impedance[ODT_OFF][3] = sw_impedance[ODT_ON][3];