summaryrefslogtreecommitdiff
path: root/src/soc/rockchip/rk3399/sdram.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/rockchip/rk3399/sdram.c')
-rw-r--r--src/soc/rockchip/rk3399/sdram.c164
1 files changed, 86 insertions, 78 deletions
diff --git a/src/soc/rockchip/rk3399/sdram.c b/src/soc/rockchip/rk3399/sdram.c
index ab16f723bd..6a0a15056d 100644
--- a/src/soc/rockchip/rk3399/sdram.c
+++ b/src/soc/rockchip/rk3399/sdram.c
@@ -701,15 +701,95 @@ static int data_training_wl(u32 channel, const struct rk3399_sdram_params *param
return 0;
}
+static int data_training_rg(u32 channel, const struct rk3399_sdram_params *params)
+{
+ u32 *denali_pi = rk3399_ddr_pi[channel]->denali_pi;
+ u32 *denali_phy = rk3399_ddr_publ[channel]->denali_phy;
+ u32 rank = params->ch[channel].rank;
+ u32 obs_0, obs_1, obs_2, obs_3, obs_err;
+ u32 reg_value = 0;
+ u32 i, tmp;
+
+ /*
+ * The differential signal of DQS needs to keep low level
+ * before gate training. RPULL will connect 4Kn from PADP
+ * to VSS and a 4Kn from PADN to VDDQ to ensure it.
+ * But if it has PHY side ODT connect at this time,
+ * it will change the DQS signal level. So disable PHY
+ * side ODT before gate training and restore ODT state
+ * after gate training.
+ */
+ if (params->dramtype != LPDDR4) {
+ reg_value = (read32(&denali_phy[6]) >> 24) & 0x7;
+
+ /*
+ * phy_dqs_tsel_enable_X 3bits
+ * DENALI_PHY_6/134/262/390 offset_24
+ */
+ clrbits32(&denali_phy[6], 0x7 << 24);
+ clrbits32(&denali_phy[134], 0x7 << 24);
+ clrbits32(&denali_phy[262], 0x7 << 24);
+ clrbits32(&denali_phy[390], 0x7 << 24);
+ }
+ for (i = 0; i < rank; i++) {
+ select_per_cs_training_index(channel, i);
+ /* PI_80 PI_RDLVL_GATE_EN:RW:24:2 */
+ clrsetbits32(&denali_pi[80], 0x3 << 24, 0x2 << 24);
+ /*
+ * PI_74 PI_RDLVL_GATE_REQ:WR:16:1
+ * PI_RDLVL_CS:RW:24:2
+ */
+ clrsetbits32(&denali_pi[74], (0x1 << 16) | (0x3 << 24),
+ (0x1 << 16) | (i << 24));
+
+ while (1) {
+ /* PI_174 PI_INT_STATUS:RD:8:18 */
+ tmp = read32(&denali_pi[174]) >> 8;
+
+ /*
+ * check status obs
+ * PHY_43/171/299/427
+ * PHY_GTLVL_STATUS_OBS_x:16:8
+ */
+ obs_0 = read32(&denali_phy[43]);
+ obs_1 = read32(&denali_phy[171]);
+ obs_2 = read32(&denali_phy[299]);
+ obs_3 = read32(&denali_phy[427]);
+ if (((obs_0 >> (16 + 6)) & 0x3) || ((obs_1 >> (16 + 6)) & 0x3)
+ || ((obs_2 >> (16 + 6)) & 0x3) || ((obs_3 >> (16 + 6)) & 0x3))
+ obs_err = 1;
+ if ((((tmp >> 9) & 0x1) == 0x1) && (((tmp >> 13) & 0x1) == 0x1)
+ && (((tmp >> 3) & 0x1) == 0x0) && (obs_err == 0))
+ break;
+ else if ((((tmp >> 3) & 0x1) == 0x1) || (obs_err == 1))
+ return -1;
+ }
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+ write32((&denali_pi[175]), 0x00003f7c);
+ }
+ clrbits32(&denali_pi[80], 0x3 << 24);
+
+ if (params->dramtype != LPDDR4) {
+ /*
+ * phy_dqs_tsel_enable_X 3bits
+ * DENALI_PHY_6/134/262/390 offset_24
+ */
+ tmp = reg_value << 24;
+ clrsetbits32(&denali_phy[6], 0x7 << 24, tmp);
+ clrsetbits32(&denali_phy[134], 0x7 << 24, tmp);
+ clrsetbits32(&denali_phy[262], 0x7 << 24, tmp);
+ clrsetbits32(&denali_phy[390], 0x7 << 24, tmp);
+ }
+ return 0;
+}
+
static int data_training(u32 channel, const struct rk3399_sdram_params *params,
u32 training_flag)
{
u32 *denali_pi = rk3399_ddr_pi[channel]->denali_pi;
u32 *denali_phy = rk3399_ddr_publ[channel]->denali_phy;
u32 i, tmp;
- u32 obs_0, obs_1, obs_2, obs_3, obs_err = 0;
u32 rank = params->ch[channel].rank;
- u32 reg_value = 0;
int ret;
/* PHY_927 PHY_PAD_DQS_DRIVE RPULL offset_22 */
@@ -750,82 +830,10 @@ static int data_training(u32 channel, const struct rk3399_sdram_params *params,
/* read gate training(LPDDR4,LPDDR3,DDR3 support) */
if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING) {
-
- /*
- * The differential signal of DQS needs to keep low level
- * before gate training. RPULL will connect 4Kn from PADP
- * to VSS and a 4Kn from PADN to VDDQ to ensure it.
- * But if it has PHY side ODT connect at this time,
- * it will change the DQS signal level. So disable PHY
- * side ODT before gate training and restore ODT state
- * after gate training.
- */
- if (params->dramtype != LPDDR4) {
- reg_value = (read32(&denali_phy[6]) >> 24) & 0x7;
-
- /*
- * phy_dqs_tsel_enable_X 3bits
- * DENALI_PHY_6/134/262/390 offset_24
- */
- clrbits32(&denali_phy[6], 0x7 << 24);
- clrbits32(&denali_phy[134], 0x7 << 24);
- clrbits32(&denali_phy[262], 0x7 << 24);
- clrbits32(&denali_phy[390], 0x7 << 24);
- }
- for (i = 0; i < rank; i++) {
- select_per_cs_training_index(channel, i);
- /* PI_80 PI_RDLVL_GATE_EN:RW:24:2 */
- clrsetbits32(&denali_pi[80], 0x3 << 24, 0x2 << 24);
- /*
- * PI_74 PI_RDLVL_GATE_REQ:WR:16:1
- * PI_RDLVL_CS:RW:24:2
- */
- clrsetbits32(&denali_pi[74],
- (0x1 << 16) | (0x3 << 24),
- (0x1 << 16) | (i << 24));
-
- while (1) {
- /* PI_174 PI_INT_STATUS:RD:8:18 */
- tmp = read32(&denali_pi[174]) >> 8;
-
- /*
- * check status obs
- * PHY_43/171/299/427
- * PHY_GTLVL_STATUS_OBS_x:16:8
- */
- obs_0 = read32(&denali_phy[43]);
- obs_1 = read32(&denali_phy[171]);
- obs_2 = read32(&denali_phy[299]);
- obs_3 = read32(&denali_phy[427]);
- if (((obs_0 >> (16 + 6)) & 0x3) ||
- ((obs_1 >> (16 + 6)) & 0x3) ||
- ((obs_2 >> (16 + 6)) & 0x3) ||
- ((obs_3 >> (16 + 6)) & 0x3))
- obs_err = 1;
- if ((((tmp >> 9) & 0x1) == 0x1) &&
- (((tmp >> 13) & 0x1) == 0x1) &&
- (((tmp >> 3) & 0x1) == 0x0) &&
- (obs_err == 0))
- break;
- else if ((((tmp >> 3) & 0x1) == 0x1) ||
- (obs_err == 1))
- return -1;
- }
- /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
- write32((&denali_pi[175]), 0x00003f7c);
- }
- clrbits32(&denali_pi[80], 0x3 << 24);
-
- if (params->dramtype != LPDDR4) {
- /*
- * phy_dqs_tsel_enable_X 3bits
- * DENALI_PHY_6/134/262/390 offset_24
- */
- tmp = reg_value << 24;
- clrsetbits32(&denali_phy[6], 0x7 << 24, tmp);
- clrsetbits32(&denali_phy[134], 0x7 << 24, tmp);
- clrsetbits32(&denali_phy[262], 0x7 << 24, tmp);
- clrsetbits32(&denali_phy[390], 0x7 << 24, tmp);
+ ret = data_training_rg(channel, params);
+ if (ret) {
+ printk(BIOS_ERR, "RG training failed\n");
+ return ret;
}
}