[U-Boot] [PATCH v3 00/18] ram: rk3399: Add rank detection

This is v3, version of dynamic rank detection changes from previous lpddr4 changes[1].
rank detection would required for probing single channel ddr configuration like NanoPi NEO4.
Changes for v3: - rebase in master - order them in proper way
[1] https://patchwork.ozlabs.org/cover/1116734/
Any inputs? Jagan.
Jagan Teki (18): ram: rk3399: Handle data training return types ram: rk3399: Clear PI_175 interrupts in data training ram: rk3399: Use rank mask in ca data training ram: rk3399: Use rank mask in wdql data training ram: rk3399: Add phy pctrl reset support ram: rk3399: Move pwrup_srefresh_exit to dram_info ram: rk3399: Add pctl start support ram: rockchip: Add initial Kconfig debug_uart: Add printdec ram: rockchip: Add debug sdram driver ram: rockchip: debug: Add sdram_print_ddr_info ram: rockchip: debug: Get the cs capacity ram: rk3399: debug: Add sdram_print_stride ram: rk3399: Compute stride for 2 channels ram: rk3399: Compute stride for 1 channel a ram: rk3399: Add rank detection support ram: rk3399: Enable sdram debug functions rockchip: dts: rk3399: nanopi-neo4: Use DDR3-1866 dtsi
arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi | 1 + .../include/asm/arch-rockchip/sdram_common.h | 21 + drivers/ram/Kconfig | 1 + drivers/ram/rockchip/Kconfig | 26 ++ drivers/ram/rockchip/Makefile | 3 +- drivers/ram/rockchip/sdram_debug.c | 147 +++++++ drivers/ram/rockchip/sdram_rk3399.c | 366 +++++++++++++++--- include/debug_uart.h | 19 + 8 files changed, 529 insertions(+), 55 deletions(-) create mode 100644 drivers/ram/rockchip/Kconfig create mode 100644 drivers/ram/rockchip/sdram_debug.c

data trainings calls like ca, wl, rg, rl, wdql have proper return types with -EIO and the return type missed to handle in data_training function.
This patch, add proper return type checks along with useful debug statement on each data training calls.
Incidentally this would help to prevent the sdram initialization hang for single channel dram and when the code is trying to initialize second channel with proper return type of relevant data training call might failed.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com --- drivers/ram/rockchip/sdram_rk3399.c | 50 ++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 12 deletions(-)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 492b0975dd..e9c0fdf2d4 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -887,6 +887,7 @@ static int data_training(const struct chan_info *chan, u32 channel, u32 training_flag) { u32 *denali_phy = chan->publ->denali_phy; + int ret;
/* PHY_927 PHY_PAD_DQS_DRIVE RPULL offset_22 */ setbits_le32(&denali_phy[927], (1 << 22)); @@ -907,24 +908,49 @@ static int data_training(const struct chan_info *chan, u32 channel, }
/* ca training(LPDDR4,LPDDR3 support) */ - if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING) - data_training_ca(chan, channel, params); + if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING) { + ret = data_training_ca(chan, channel, params); + if (ret < 0) { + debug("%s: data training ca failed\n", __func__); + return ret; + } + }
/* write leveling(LPDDR4,LPDDR3,DDR3 support) */ - if ((training_flag & PI_WRITE_LEVELING) == PI_WRITE_LEVELING) - data_training_wl(chan, channel, params); + if ((training_flag & PI_WRITE_LEVELING) == PI_WRITE_LEVELING) { + ret = data_training_wl(chan, channel, params); + if (ret < 0) { + debug("%s: data training wl failed\n", __func__); + return ret; + } + }
/* read gate training(LPDDR4,LPDDR3,DDR3 support) */ - if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING) - data_training_rg(chan, channel, params); + if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING) { + ret = data_training_rg(chan, channel, params); + if (ret < 0) { + debug("%s: data training rg failed\n", __func__); + return ret; + } + }
/* read leveling(LPDDR4,LPDDR3,DDR3 support) */ - if ((training_flag & PI_READ_LEVELING) == PI_READ_LEVELING) - data_training_rl(chan, channel, params); + if ((training_flag & PI_READ_LEVELING) == PI_READ_LEVELING) { + ret = data_training_rl(chan, channel, params); + if (ret < 0) { + debug("%s: data training rl failed\n", __func__); + return ret; + } + }
/* wdq leveling(LPDDR4 support) */ - if ((training_flag & PI_WDQ_LEVELING) == PI_WDQ_LEVELING) - data_training_wdql(chan, channel, params); + if ((training_flag & PI_WDQ_LEVELING) == PI_WDQ_LEVELING) { + ret = data_training_wdql(chan, channel, params); + if (ret < 0) { + debug("%s: data training wdql failed\n", __func__); + return ret; + } + }
/* PHY_927 PHY_PAD_DQS_DRIVE RPULL offset_22 */ clrbits_le32(&denali_phy[927], (1 << 22)); @@ -1062,7 +1088,7 @@ static int switch_to_phy_index1(struct dram_info *dram, clrsetbits_le32(&denali_phy[896], (0x3 << 8) | 1, 1 << 8); ret = data_training(&dram->chan[channel], channel, params, PI_FULL_TRAINING); - if (ret) { + if (ret < 0) { debug("index1 training failed\n"); return ret; } @@ -1108,7 +1134,7 @@ static int sdram_init(struct dram_info *dram, udelay(10);
if (data_training(chan, channel, params, PI_FULL_TRAINING)) { - printf("SDRAM initialization failed, reset\n"); + printf("%s: data training failed\n", __func__); return -EIO; }

On 2019/7/16 上午2:28, Jagan Teki wrote:
data trainings calls like ca, wl, rg, rl, wdql have proper return types with -EIO and the return type missed to handle in data_training function.
This patch, add proper return type checks along with useful debug statement on each data training calls.
Incidentally this would help to prevent the sdram initialization hang for single channel dram and when the code is trying to initialize second channel with proper return type of relevant data training call might failed.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
drivers/ram/rockchip/sdram_rk3399.c | 50 ++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 12 deletions(-)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 492b0975dd..e9c0fdf2d4 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -887,6 +887,7 @@ static int data_training(const struct chan_info *chan, u32 channel, u32 training_flag) { u32 *denali_phy = chan->publ->denali_phy;
int ret;
/* PHY_927 PHY_PAD_DQS_DRIVE RPULL offset_22 */ setbits_le32(&denali_phy[927], (1 << 22));
@@ -907,24 +908,49 @@ static int data_training(const struct chan_info *chan, u32 channel, }
/* ca training(LPDDR4,LPDDR3 support) */
- if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING)
data_training_ca(chan, channel, params);
if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING) {
ret = data_training_ca(chan, channel, params);
if (ret < 0) {
debug("%s: data training ca failed\n", __func__);
return ret;
}
}
/* write leveling(LPDDR4,LPDDR3,DDR3 support) */
- if ((training_flag & PI_WRITE_LEVELING) == PI_WRITE_LEVELING)
data_training_wl(chan, channel, params);
if ((training_flag & PI_WRITE_LEVELING) == PI_WRITE_LEVELING) {
ret = data_training_wl(chan, channel, params);
if (ret < 0) {
debug("%s: data training wl failed\n", __func__);
return ret;
}
}
/* read gate training(LPDDR4,LPDDR3,DDR3 support) */
- if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING)
data_training_rg(chan, channel, params);
if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING) {
ret = data_training_rg(chan, channel, params);
if (ret < 0) {
debug("%s: data training rg failed\n", __func__);
return ret;
}
}
/* read leveling(LPDDR4,LPDDR3,DDR3 support) */
- if ((training_flag & PI_READ_LEVELING) == PI_READ_LEVELING)
data_training_rl(chan, channel, params);
if ((training_flag & PI_READ_LEVELING) == PI_READ_LEVELING) {
ret = data_training_rl(chan, channel, params);
if (ret < 0) {
debug("%s: data training rl failed\n", __func__);
return ret;
}
}
/* wdq leveling(LPDDR4 support) */
- if ((training_flag & PI_WDQ_LEVELING) == PI_WDQ_LEVELING)
data_training_wdql(chan, channel, params);
if ((training_flag & PI_WDQ_LEVELING) == PI_WDQ_LEVELING) {
ret = data_training_wdql(chan, channel, params);
if (ret < 0) {
debug("%s: data training wdql failed\n", __func__);
return ret;
}
}
/* PHY_927 PHY_PAD_DQS_DRIVE RPULL offset_22 */ clrbits_le32(&denali_phy[927], (1 << 22));
@@ -1062,7 +1088,7 @@ static int switch_to_phy_index1(struct dram_info *dram, clrsetbits_le32(&denali_phy[896], (0x3 << 8) | 1, 1 << 8); ret = data_training(&dram->chan[channel], channel, params, PI_FULL_TRAINING);
if (ret) {
}if (ret < 0) { debug("index1 training failed\n"); return ret;
@@ -1108,7 +1134,7 @@ static int sdram_init(struct dram_info *dram, udelay(10);
if (data_training(chan, channel, params, PI_FULL_TRAINING)) {
printf("SDRAM initialization failed, reset\n");
}printf("%s: data training failed\n", __func__); return -EIO;

Clear the PI_175 interrupts before processing actual data training in all relevant calls.
This would help to clear interrupt from previous training.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com --- drivers/ram/rockchip/sdram_rk3399.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index e9c0fdf2d4..fe26144f27 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -627,6 +627,9 @@ static int data_training_ca(const struct chan_info *chan, u32 channel, u32 obs_0, obs_1, obs_2, obs_err = 0; u32 rank = params->ch[channel].cap_info.rank;
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ + writel(0x00003f7c, (&denali_pi[175])); + for (i = 0; i < rank; i++) { select_per_cs_training_index(chan, i);
@@ -681,6 +684,9 @@ static int data_training_wl(const struct chan_info *chan, u32 channel, u32 obs_0, obs_1, obs_2, obs_3, obs_err = 0; u32 rank = params->ch[channel].cap_info.rank;
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ + writel(0x00003f7c, (&denali_pi[175])); + for (i = 0; i < rank; i++) { select_per_cs_training_index(chan, i);
@@ -740,6 +746,9 @@ static int data_training_rg(const struct chan_info *chan, u32 channel, u32 obs_0, obs_1, obs_2, obs_3, obs_err = 0; u32 rank = params->ch[channel].cap_info.rank;
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ + writel(0x00003f7c, (&denali_pi[175])); + for (i = 0; i < rank; i++) { select_per_cs_training_index(chan, i);
@@ -799,6 +808,9 @@ static int data_training_rl(const struct chan_info *chan, u32 channel, u32 i, tmp; u32 rank = params->ch[channel].cap_info.rank;
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ + writel(0x00003f7c, (&denali_pi[175])); + for (i = 0; i < rank; i++) { select_per_cs_training_index(chan, i);
@@ -844,6 +856,9 @@ static int data_training_wdql(const struct chan_info *chan, u32 channel, u32 i, tmp; u32 rank = params->ch[channel].cap_info.rank;
+ /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ + writel(0x00003f7c, (&denali_pi[175])); + for (i = 0; i < rank; i++) { select_per_cs_training_index(chan, i);

On 2019/7/16 上午2:28, Jagan Teki wrote:
Clear the PI_175 interrupts before processing actual data training in all relevant calls.
This would help to clear interrupt from previous training.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
drivers/ram/rockchip/sdram_rk3399.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index e9c0fdf2d4..fe26144f27 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -627,6 +627,9 @@ static int data_training_ca(const struct chan_info *chan, u32 channel, u32 obs_0, obs_1, obs_2, obs_err = 0; u32 rank = params->ch[channel].cap_info.rank;
- /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
- writel(0x00003f7c, (&denali_pi[175]));
- for (i = 0; i < rank; i++) { select_per_cs_training_index(chan, i);
@@ -681,6 +684,9 @@ static int data_training_wl(const struct chan_info *chan, u32 channel, u32 obs_0, obs_1, obs_2, obs_3, obs_err = 0; u32 rank = params->ch[channel].cap_info.rank;
- /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
- writel(0x00003f7c, (&denali_pi[175]));
- for (i = 0; i < rank; i++) { select_per_cs_training_index(chan, i);
@@ -740,6 +746,9 @@ static int data_training_rg(const struct chan_info *chan, u32 channel, u32 obs_0, obs_1, obs_2, obs_3, obs_err = 0; u32 rank = params->ch[channel].cap_info.rank;
- /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
- writel(0x00003f7c, (&denali_pi[175]));
- for (i = 0; i < rank; i++) { select_per_cs_training_index(chan, i);
@@ -799,6 +808,9 @@ static int data_training_rl(const struct chan_info *chan, u32 channel, u32 i, tmp; u32 rank = params->ch[channel].cap_info.rank;
- /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
- writel(0x00003f7c, (&denali_pi[175]));
- for (i = 0; i < rank; i++) { select_per_cs_training_index(chan, i);
@@ -844,6 +856,9 @@ static int data_training_wdql(const struct chan_info *chan, u32 channel, u32 i, tmp; u32 rank = params->ch[channel].cap_info.rank;
- /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
- writel(0x00003f7c, (&denali_pi[175]));
- for (i = 0; i < rank; i++) { select_per_cs_training_index(chan, i);

Add rank_mask based on the rank number, this would keep the ca data training loop based on the desired rank mask value instead of looping for all values.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com --- drivers/ram/rockchip/sdram_rk3399.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index fe26144f27..b98df20fa5 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -626,11 +626,17 @@ static int data_training_ca(const struct chan_info *chan, u32 channel, u32 i, tmp; u32 obs_0, obs_1, obs_2, obs_err = 0; u32 rank = params->ch[channel].cap_info.rank; + u32 rank_mask;
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ writel(0x00003f7c, (&denali_pi[175]));
- for (i = 0; i < rank; i++) { + rank_mask = (rank == 1) ? 0x1 : 0x3; + + for (i = 0; i < 4; i++) { + if (!(rank_mask & (1 << i))) + continue; + select_per_cs_training_index(chan, i);
/* PI_100 PI_CALVL_EN:RW:8:2 */

On 2019/7/16 上午2:28, Jagan Teki wrote:
Add rank_mask based on the rank number, this would keep the ca data training loop based on the desired rank mask value instead of looping for all values.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
drivers/ram/rockchip/sdram_rk3399.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index fe26144f27..b98df20fa5 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -626,11 +626,17 @@ static int data_training_ca(const struct chan_info *chan, u32 channel, u32 i, tmp; u32 obs_0, obs_1, obs_2, obs_err = 0; u32 rank = params->ch[channel].cap_info.rank;
u32 rank_mask;
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ writel(0x00003f7c, (&denali_pi[175]));
- for (i = 0; i < rank; i++) {
rank_mask = (rank == 1) ? 0x1 : 0x3;
for (i = 0; i < 4; i++) {
if (!(rank_mask & (1 << i)))
continue;
select_per_cs_training_index(chan, i);
/* PI_100 PI_CALVL_EN:RW:8:2 */

Add rank_mask based on the rank number, this would keep the wdql data training loop based on the desired rank mask value instead of looping for all values.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com --- drivers/ram/rockchip/sdram_rk3399.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index b98df20fa5..16bd9427a6 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -861,11 +861,17 @@ static int data_training_wdql(const struct chan_info *chan, u32 channel, u32 *denali_pi = chan->pi->denali_pi; u32 i, tmp; u32 rank = params->ch[channel].cap_info.rank; + u32 rank_mask;
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ writel(0x00003f7c, (&denali_pi[175]));
- for (i = 0; i < rank; i++) { + rank_mask = (rank == 1) ? 0x1 : 0x3; + + for (i = 0; i < 4; i++) { + if (!(rank_mask & (1 << i))) + continue; + select_per_cs_training_index(chan, i);
/*

On 2019/7/16 上午2:28, Jagan Teki wrote:
Add rank_mask based on the rank number, this would keep the wdql data training loop based on the desired rank mask value instead of looping for all values.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
drivers/ram/rockchip/sdram_rk3399.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index b98df20fa5..16bd9427a6 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -861,11 +861,17 @@ static int data_training_wdql(const struct chan_info *chan, u32 channel, u32 *denali_pi = chan->pi->denali_pi; u32 i, tmp; u32 rank = params->ch[channel].cap_info.rank;
u32 rank_mask;
/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ writel(0x00003f7c, (&denali_pi[175]));
- for (i = 0; i < rank; i++) {
rank_mask = (rank == 1) ? 0x1 : 0x3;
for (i = 0; i < 4; i++) {
if (!(rank_mask & (1 << i)))
continue;
select_per_cs_training_index(chan, i);
/*

Add support for phy pctrl reset support for both channel 0, 1.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com --- drivers/ram/rockchip/sdram_rk3399.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 16bd9427a6..a5da985e1a 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -35,6 +35,10 @@ #define PHY_DRV_ODT_40 0xe #define PHY_DRV_ODT_34_3 0xf
+#define CRU_SFTRST_DDR_CTRL(ch, n) ((0x1 << (8 + 16 + (ch) * 4)) | \ + ((n) << (8 + (ch) * 4))) +#define CRU_SFTRST_DDR_PHY(ch, n) ((0x1 << (9 + 16 + (ch) * 4)) | \ + ((n) << (9 + (ch) * 4))) struct chan_info { struct rk3399_ddr_pctl_regs *pctl; struct rk3399_ddr_pi_regs *pi; @@ -79,6 +83,29 @@ static void copy_to_reg(u32 *dest, const u32 *src, u32 n) } }
+static void rkclk_ddr_reset(struct rk3399_cru *cru, u32 channel, u32 ctl, + u32 phy) +{ + channel &= 0x1; + ctl &= 0x1; + phy &= 0x1; + writel(CRU_SFTRST_DDR_CTRL(channel, ctl) | + CRU_SFTRST_DDR_PHY(channel, phy), + &cru->softrst_con[4]); +} + +static void phy_pctrl_reset(struct rk3399_cru *cru, u32 channel) +{ + rkclk_ddr_reset(cru, channel, 1, 1); + udelay(10); + + rkclk_ddr_reset(cru, channel, 1, 0); + udelay(10); + + rkclk_ddr_reset(cru, channel, 0, 0); + udelay(10); +} + static void phy_dll_bypass_set(struct rk3399_ddr_publ_regs *ddr_publ_regs, u32 freq) { @@ -1129,6 +1156,7 @@ static int sdram_init(struct dram_info *dram, { unsigned char dramtype = params->base.dramtype; unsigned int ddr_freq = params->base.ddr_freq; + struct rk3399_cru *cru = dram->cru; int channel; int ret;
@@ -1145,6 +1173,7 @@ static int sdram_init(struct dram_info *dram, const struct chan_info *chan = &dram->chan[channel]; struct rk3399_ddr_publ_regs *publ = chan->publ;
+ phy_pctrl_reset(cru, channel); phy_dll_bypass_set(publ, ddr_freq);
if (channel >= params->base.num_channels)

On 2019/7/16 上午2:28, Jagan Teki wrote:
Add support for phy pctrl reset support for both channel 0, 1.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
drivers/ram/rockchip/sdram_rk3399.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 16bd9427a6..a5da985e1a 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -35,6 +35,10 @@ #define PHY_DRV_ODT_40 0xe #define PHY_DRV_ODT_34_3 0xf
+#define CRU_SFTRST_DDR_CTRL(ch, n) ((0x1 << (8 + 16 + (ch) * 4)) | \
((n) << (8 + (ch) * 4)))
+#define CRU_SFTRST_DDR_PHY(ch, n) ((0x1 << (9 + 16 + (ch) * 4)) | \
struct chan_info { struct rk3399_ddr_pctl_regs *pctl; struct rk3399_ddr_pi_regs *pi;((n) << (9 + (ch) * 4)))
@@ -79,6 +83,29 @@ static void copy_to_reg(u32 *dest, const u32 *src, u32 n) } }
+static void rkclk_ddr_reset(struct rk3399_cru *cru, u32 channel, u32 ctl,
u32 phy)
+{
- channel &= 0x1;
- ctl &= 0x1;
- phy &= 0x1;
- writel(CRU_SFTRST_DDR_CTRL(channel, ctl) |
CRU_SFTRST_DDR_PHY(channel, phy),
&cru->softrst_con[4]);
+}
+static void phy_pctrl_reset(struct rk3399_cru *cru, u32 channel) +{
- rkclk_ddr_reset(cru, channel, 1, 1);
- udelay(10);
- rkclk_ddr_reset(cru, channel, 1, 0);
- udelay(10);
- rkclk_ddr_reset(cru, channel, 0, 0);
- udelay(10);
+}
- static void phy_dll_bypass_set(struct rk3399_ddr_publ_regs *ddr_publ_regs, u32 freq) {
@@ -1129,6 +1156,7 @@ static int sdram_init(struct dram_info *dram, { unsigned char dramtype = params->base.dramtype; unsigned int ddr_freq = params->base.ddr_freq;
- struct rk3399_cru *cru = dram->cru; int channel; int ret;
@@ -1145,6 +1173,7 @@ static int sdram_init(struct dram_info *dram, const struct chan_info *chan = &dram->chan[channel]; struct rk3399_ddr_publ_regs *publ = chan->publ;
phy_pctrl_reset(cru, channel);
phy_dll_bypass_set(publ, ddr_freq);
if (channel >= params->base.num_channels)

Add pwrup_srefresh_exit to be part of dram_info so-that the it can help to support pwrup_srefresh_exit in individual channels while starting pctl in future.
No functionality change.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com --- drivers/ram/rockchip/sdram_rk3399.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index a5da985e1a..6e944cafd9 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -49,6 +49,7 @@ struct chan_info { struct dram_info { #if defined(CONFIG_TPL_BUILD) || \ (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD)) + u32 pwrup_srefresh_exit; struct chan_info chan[2]; struct clk ddr_clk; struct rk3399_cru *cru; @@ -487,8 +488,8 @@ static int phy_io_config(const struct chan_info *chan, return 0; }
-static int pctl_cfg(const struct chan_info *chan, u32 channel, - const struct rk3399_sdram_params *params) +static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan, + u32 channel, const struct rk3399_sdram_params *params) { u32 *denali_ctl = chan->pctl->denali_ctl; u32 *denali_pi = chan->pi->denali_pi; @@ -496,7 +497,6 @@ static int pctl_cfg(const struct chan_info *chan, u32 channel, const u32 *params_ctl = params->pctl_regs.denali_ctl; const u32 *params_phy = params->phy_regs.denali_phy; u32 tmp, tmp1, tmp2; - u32 pwrup_srefresh_exit; int ret; const ulong timeout_ms = 200;
@@ -518,7 +518,8 @@ static int pctl_cfg(const struct chan_info *chan, u32 channel, writel(params->phy_regs.denali_phy[911], &denali_phy[911]); writel(params->phy_regs.denali_phy[912], &denali_phy[912]);
- pwrup_srefresh_exit = readl(&denali_ctl[68]) & PWRUP_SREFRESH_EXIT; + dram->pwrup_srefresh_exit = readl(&denali_ctl[68]) & + PWRUP_SREFRESH_EXIT; clrbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT);
/* PHY_DLL_RST_EN */ @@ -594,7 +595,7 @@ static int pctl_cfg(const struct chan_info *chan, u32 channel, debug("DRAM (%s): phy locked after %ld ms\n", __func__, get_timer(tmp));
clrsetbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT, - pwrup_srefresh_exit); + dram->pwrup_srefresh_exit); return 0; }
@@ -1179,7 +1180,7 @@ static int sdram_init(struct dram_info *dram, if (channel >= params->base.num_channels) continue;
- ret = pctl_cfg(chan, channel, params); + ret = pctl_cfg(dram, chan, channel, params); if (ret < 0) { printf("%s: pctl config failed\n", __func__); return ret;

On 2019/7/16 上午2:28, Jagan Teki wrote:
Add pwrup_srefresh_exit to be part of dram_info so-that the it can help to support pwrup_srefresh_exit in individual channels while starting pctl in future.
No functionality change.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
drivers/ram/rockchip/sdram_rk3399.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index a5da985e1a..6e944cafd9 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -49,6 +49,7 @@ struct chan_info { struct dram_info { #if defined(CONFIG_TPL_BUILD) || \ (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD))
- u32 pwrup_srefresh_exit; struct chan_info chan[2]; struct clk ddr_clk; struct rk3399_cru *cru;
@@ -487,8 +488,8 @@ static int phy_io_config(const struct chan_info *chan, return 0; }
-static int pctl_cfg(const struct chan_info *chan, u32 channel,
const struct rk3399_sdram_params *params)
+static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan,
{ u32 *denali_ctl = chan->pctl->denali_ctl; u32 *denali_pi = chan->pi->denali_pi;u32 channel, const struct rk3399_sdram_params *params)
@@ -496,7 +497,6 @@ static int pctl_cfg(const struct chan_info *chan, u32 channel, const u32 *params_ctl = params->pctl_regs.denali_ctl; const u32 *params_phy = params->phy_regs.denali_phy; u32 tmp, tmp1, tmp2;
- u32 pwrup_srefresh_exit; int ret; const ulong timeout_ms = 200;
@@ -518,7 +518,8 @@ static int pctl_cfg(const struct chan_info *chan, u32 channel, writel(params->phy_regs.denali_phy[911], &denali_phy[911]); writel(params->phy_regs.denali_phy[912], &denali_phy[912]);
- pwrup_srefresh_exit = readl(&denali_ctl[68]) & PWRUP_SREFRESH_EXIT;
dram->pwrup_srefresh_exit = readl(&denali_ctl[68]) &
PWRUP_SREFRESH_EXIT;
clrbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT);
/* PHY_DLL_RST_EN */
@@ -594,7 +595,7 @@ static int pctl_cfg(const struct chan_info *chan, u32 channel, debug("DRAM (%s): phy locked after %ld ms\n", __func__, get_timer(tmp));
clrsetbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT,
pwrup_srefresh_exit);
return 0; }dram->pwrup_srefresh_exit);
@@ -1179,7 +1180,7 @@ static int sdram_init(struct dram_info *dram, if (channel >= params->base.num_channels) continue;
ret = pctl_cfg(chan, channel, params);
if (ret < 0) { printf("%s: pctl config failed\n", __func__); return ret;ret = pctl_cfg(dram, chan, channel, params);

Add support for pctl start for both channel 0, 1 control and phy registers.
This would also handle pwrup_srefresh_exit init based on the channel number.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com --- drivers/ram/rockchip/sdram_rk3399.c | 75 +++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 20 deletions(-)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 6e944cafd9..084c949728 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -49,10 +49,11 @@ struct chan_info { struct dram_info { #if defined(CONFIG_TPL_BUILD) || \ (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD)) - u32 pwrup_srefresh_exit; + u32 pwrup_srefresh_exit[2]; struct chan_info chan[2]; struct clk ddr_clk; struct rk3399_cru *cru; + struct rk3399_grf_regs *grf; struct rk3399_pmucru *pmucru; struct rk3399_pmusgrf_regs *pmusgrf; struct rk3399_ddr_cic_regs *cic; @@ -73,6 +74,11 @@ struct rockchip_dmc_plat { struct regmap *map; };
+static void *get_ddrc0_con(struct dram_info *dram, u8 channel) +{ + return (channel == 0) ? &dram->grf->ddrc0_con0 : &dram->grf->ddrc0_con1; +} + static void copy_to_reg(u32 *dest, const u32 *src, u32 n) { int i; @@ -328,6 +334,48 @@ static void set_ds_odt(const struct chan_info *chan, clrsetbits_le32(&denali_phy[930], 0x1 << 17, reg_value); }
+static void pctl_start(struct dram_info *dram, u8 channel) +{ + const struct chan_info *chan = &dram->chan[channel]; + u32 *denali_ctl = chan->pctl->denali_ctl; + u32 *denali_phy = chan->publ->denali_phy; + u32 *ddrc0_con = get_ddrc0_con(dram, channel); + u32 count = 0; + u32 byte, tmp; + + writel(0x01000000, &ddrc0_con); + + clrsetbits_le32(&denali_phy[957], 0x3 << 24, 0x2 << 24); + + while (!(readl(&denali_ctl[203]) & (1 << 3))) { + if (count > 1000) { + printf("%s: Failed to init pctl for channel %d\n", + __func__, channel); + while (1) + ; + } + + udelay(1); + count++; + } + + writel(0x01000100, &ddrc0_con); + + for (byte = 0; byte < 4; byte++) { + tmp = 0x820; + writel((tmp << 16) | tmp, &denali_phy[53 + (128 * byte)]); + writel((tmp << 16) | tmp, &denali_phy[54 + (128 * byte)]); + writel((tmp << 16) | tmp, &denali_phy[55 + (128 * byte)]); + writel((tmp << 16) | tmp, &denali_phy[56 + (128 * byte)]); + writel((tmp << 16) | tmp, &denali_phy[57 + (128 * byte)]); + + clrsetbits_le32(&denali_phy[58 + (128 * byte)], 0xffff, tmp); + } + + clrsetbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT, + dram->pwrup_srefresh_exit[channel]); +} + static int phy_io_config(const struct chan_info *chan, const struct rk3399_sdram_params *params) { @@ -498,7 +546,6 @@ static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan, const u32 *params_phy = params->phy_regs.denali_phy; u32 tmp, tmp1, tmp2; int ret; - const ulong timeout_ms = 200;
/* * work around controller bug: @@ -518,8 +565,8 @@ static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan, writel(params->phy_regs.denali_phy[911], &denali_phy[911]); writel(params->phy_regs.denali_phy[912], &denali_phy[912]);
- dram->pwrup_srefresh_exit = readl(&denali_ctl[68]) & - PWRUP_SREFRESH_EXIT; + dram->pwrup_srefresh_exit[channel] = readl(&denali_ctl[68]) & + PWRUP_SREFRESH_EXIT; clrbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT);
/* PHY_DLL_RST_EN */ @@ -580,22 +627,6 @@ static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan, if (ret) return ret;
- /* PHY_DLL_RST_EN */ - clrsetbits_le32(&denali_phy[957], 0x3 << 24, 0x2 << 24); - - /* Waiting for PHY and DRAM init complete */ - tmp = get_timer(0); - do { - if (get_timer(tmp) > timeout_ms) { - pr_err("DRAM (%s): phy failed to lock within %ld ms\n", - __func__, timeout_ms); - return -ETIME; - } - } while (!(readl(&denali_ctl[203]) & (1 << 3))); - debug("DRAM (%s): phy locked after %ld ms\n", __func__, get_timer(tmp)); - - clrsetbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT, - dram->pwrup_srefresh_exit); return 0; }
@@ -1186,6 +1217,9 @@ static int sdram_init(struct dram_info *dram, return ret; }
+ /* start to trigger initialization */ + pctl_start(dram, channel); + /* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */ if (dramtype == LPDDR3) udelay(10); @@ -1262,6 +1296,7 @@ static int rk3399_dmc_init(struct udevice *dev) #endif
priv->cic = syscon_get_first_range(ROCKCHIP_SYSCON_CIC); + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF); priv->pmusgrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUSGRF); priv->pmucru = rockchip_get_pmucru();

On 2019/7/16 上午2:28, Jagan Teki wrote:
Add support for pctl start for both channel 0, 1 control and phy registers.
This would also handle pwrup_srefresh_exit init based on the channel number.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
drivers/ram/rockchip/sdram_rk3399.c | 75 +++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 20 deletions(-)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 6e944cafd9..084c949728 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -49,10 +49,11 @@ struct chan_info { struct dram_info { #if defined(CONFIG_TPL_BUILD) || \ (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD))
- u32 pwrup_srefresh_exit;
- u32 pwrup_srefresh_exit[2]; struct chan_info chan[2]; struct clk ddr_clk; struct rk3399_cru *cru;
- struct rk3399_grf_regs *grf; struct rk3399_pmucru *pmucru; struct rk3399_pmusgrf_regs *pmusgrf; struct rk3399_ddr_cic_regs *cic;
@@ -73,6 +74,11 @@ struct rockchip_dmc_plat { struct regmap *map; };
+static void *get_ddrc0_con(struct dram_info *dram, u8 channel) +{
- return (channel == 0) ? &dram->grf->ddrc0_con0 : &dram->grf->ddrc0_con1;
+}
- static void copy_to_reg(u32 *dest, const u32 *src, u32 n) { int i;
@@ -328,6 +334,48 @@ static void set_ds_odt(const struct chan_info *chan, clrsetbits_le32(&denali_phy[930], 0x1 << 17, reg_value); }
+static void pctl_start(struct dram_info *dram, u8 channel) +{
- const struct chan_info *chan = &dram->chan[channel];
- u32 *denali_ctl = chan->pctl->denali_ctl;
- u32 *denali_phy = chan->publ->denali_phy;
- u32 *ddrc0_con = get_ddrc0_con(dram, channel);
- u32 count = 0;
- u32 byte, tmp;
- writel(0x01000000, &ddrc0_con);
- clrsetbits_le32(&denali_phy[957], 0x3 << 24, 0x2 << 24);
- while (!(readl(&denali_ctl[203]) & (1 << 3))) {
if (count > 1000) {
printf("%s: Failed to init pctl for channel %d\n",
__func__, channel);
while (1)
;
}
udelay(1);
count++;
- }
- writel(0x01000100, &ddrc0_con);
- for (byte = 0; byte < 4; byte++) {
tmp = 0x820;
writel((tmp << 16) | tmp, &denali_phy[53 + (128 * byte)]);
writel((tmp << 16) | tmp, &denali_phy[54 + (128 * byte)]);
writel((tmp << 16) | tmp, &denali_phy[55 + (128 * byte)]);
writel((tmp << 16) | tmp, &denali_phy[56 + (128 * byte)]);
writel((tmp << 16) | tmp, &denali_phy[57 + (128 * byte)]);
clrsetbits_le32(&denali_phy[58 + (128 * byte)], 0xffff, tmp);
- }
- clrsetbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT,
dram->pwrup_srefresh_exit[channel]);
+}
- static int phy_io_config(const struct chan_info *chan, const struct rk3399_sdram_params *params) {
@@ -498,7 +546,6 @@ static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan, const u32 *params_phy = params->phy_regs.denali_phy; u32 tmp, tmp1, tmp2; int ret;
const ulong timeout_ms = 200;
/*
- work around controller bug:
@@ -518,8 +565,8 @@ static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan, writel(params->phy_regs.denali_phy[911], &denali_phy[911]); writel(params->phy_regs.denali_phy[912], &denali_phy[912]);
- dram->pwrup_srefresh_exit = readl(&denali_ctl[68]) &
PWRUP_SREFRESH_EXIT;
dram->pwrup_srefresh_exit[channel] = readl(&denali_ctl[68]) &
PWRUP_SREFRESH_EXIT;
clrbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT);
/* PHY_DLL_RST_EN */
@@ -580,22 +627,6 @@ static int pctl_cfg(struct dram_info *dram, const struct chan_info *chan, if (ret) return ret;
- /* PHY_DLL_RST_EN */
- clrsetbits_le32(&denali_phy[957], 0x3 << 24, 0x2 << 24);
- /* Waiting for PHY and DRAM init complete */
- tmp = get_timer(0);
- do {
if (get_timer(tmp) > timeout_ms) {
pr_err("DRAM (%s): phy failed to lock within %ld ms\n",
__func__, timeout_ms);
return -ETIME;
}
- } while (!(readl(&denali_ctl[203]) & (1 << 3)));
- debug("DRAM (%s): phy locked after %ld ms\n", __func__, get_timer(tmp));
- clrsetbits_le32(&denali_ctl[68], PWRUP_SREFRESH_EXIT,
return 0; }dram->pwrup_srefresh_exit);
@@ -1186,6 +1217,9 @@ static int sdram_init(struct dram_info *dram, return ret; }
/* start to trigger initialization */
pctl_start(dram, channel);
- /* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */ if (dramtype == LPDDR3) udelay(10);
@@ -1262,6 +1296,7 @@ static int rk3399_dmc_init(struct udevice *dev) #endif
priv->cic = syscon_get_first_range(ROCKCHIP_SYSCON_CIC);
- priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF); priv->pmusgrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUSGRF); priv->pmucru = rockchip_get_pmucru();

Right now sdram drivers in rockchip SoC are built based on the SoC configs which may not be an adequate solutions while adding common or debug driver.
So, add meaningful Kconfig options start with rk3399.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com --- drivers/ram/Kconfig | 1 + drivers/ram/rockchip/Kconfig | 17 +++++++++++++++++ drivers/ram/rockchip/Makefile | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 drivers/ram/rockchip/Kconfig
diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig index fbf7d7b20f..568d8f2c6a 100644 --- a/drivers/ram/Kconfig +++ b/drivers/ram/Kconfig @@ -54,4 +54,5 @@ config K3_AM654_DDRSS config add support for the initialization of the external SDRAM devices connected to DDR subsystem.
+source "drivers/ram/rockchip/Kconfig" source "drivers/ram/stm32mp1/Kconfig" diff --git a/drivers/ram/rockchip/Kconfig b/drivers/ram/rockchip/Kconfig new file mode 100644 index 0000000000..995cb487b8 --- /dev/null +++ b/drivers/ram/rockchip/Kconfig @@ -0,0 +1,17 @@ +config RAM_ROCKCHIP + bool "Ram drivers support for Rockchip SoCs" + depends on RAM && ARCH_ROCKCHIP + default y + help + This enables support for ram drivers Rockchip SoCs. + +if RAM_ROCKCHIP + +config RAM_RK3399 + bool "Ram driver for Rockchip RK3399" + default ROCKCHIP_RK3399 + help + This enables ram drivers support for the platforms based on + Rockchip RK3399 SoC. + +endif # RAM_ROCKCHIP diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile index 5df196066d..07d4b62a9d 100644 --- a/drivers/ram/rockchip/Makefile +++ b/drivers/ram/rockchip/Makefile @@ -9,4 +9,4 @@ obj-$(CONFIG_ROCKCHIP_RK3188) = sdram_rk3188.o obj-$(CONFIG_ROCKCHIP_RK322X) = sdram_rk322x.o obj-$(CONFIG_ROCKCHIP_RK3288) = sdram_rk3288.o obj-$(CONFIG_ROCKCHIP_RK3328) = sdram_rk3328.o -obj-$(CONFIG_ROCKCHIP_RK3399) = sdram_rk3399.o +obj-$(CONFIG_RAM_RK3399) += sdram_rk3399.o

On 2019/7/16 上午2:28, Jagan Teki wrote:
Right now sdram drivers in rockchip SoC are built based on the SoC configs which may not be an adequate solutions while adding common or debug driver.
So, add meaningful Kconfig options start with rk3399.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
drivers/ram/Kconfig | 1 + drivers/ram/rockchip/Kconfig | 17 +++++++++++++++++ drivers/ram/rockchip/Makefile | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 drivers/ram/rockchip/Kconfig
diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig index fbf7d7b20f..568d8f2c6a 100644 --- a/drivers/ram/Kconfig +++ b/drivers/ram/Kconfig @@ -54,4 +54,5 @@ config K3_AM654_DDRSS config add support for the initialization of the external SDRAM devices connected to DDR subsystem.
+source "drivers/ram/rockchip/Kconfig" source "drivers/ram/stm32mp1/Kconfig" diff --git a/drivers/ram/rockchip/Kconfig b/drivers/ram/rockchip/Kconfig new file mode 100644 index 0000000000..995cb487b8 --- /dev/null +++ b/drivers/ram/rockchip/Kconfig @@ -0,0 +1,17 @@ +config RAM_ROCKCHIP
- bool "Ram drivers support for Rockchip SoCs"
- depends on RAM && ARCH_ROCKCHIP
- default y
- help
This enables support for ram drivers Rockchip SoCs.
+if RAM_ROCKCHIP
+config RAM_RK3399
- bool "Ram driver for Rockchip RK3399"
- default ROCKCHIP_RK3399
- help
This enables ram drivers support for the platforms based on
Rockchip RK3399 SoC.
+endif # RAM_ROCKCHIP diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile index 5df196066d..07d4b62a9d 100644 --- a/drivers/ram/rockchip/Makefile +++ b/drivers/ram/rockchip/Makefile @@ -9,4 +9,4 @@ obj-$(CONFIG_ROCKCHIP_RK3188) = sdram_rk3188.o obj-$(CONFIG_ROCKCHIP_RK322X) = sdram_rk322x.o obj-$(CONFIG_ROCKCHIP_RK3288) = sdram_rk3288.o obj-$(CONFIG_ROCKCHIP_RK3328) = sdram_rk3328.o -obj-$(CONFIG_ROCKCHIP_RK3399) = sdram_rk3399.o +obj-$(CONFIG_RAM_RK3399) += sdram_rk3399.o

Add printdec, this would help to print an output a decimalism value.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com --- include/debug_uart.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/include/debug_uart.h b/include/debug_uart.h index 34e8b2fc81..cd70ae1a04 100644 --- a/include/debug_uart.h +++ b/include/debug_uart.h @@ -104,6 +104,13 @@ void printhex4(uint value); */ void printhex8(uint value);
+/** + * printdec() - Output a decimalism value + * + * @value: Value to output + */ +void printdec(uint value); + #ifdef CONFIG_DEBUG_UART_ANNOUNCE #define _DEBUG_UART_ANNOUNCE printascii("<debug_uart> "); #else @@ -170,6 +177,18 @@ void printhex8(uint value); { \ printhex(value, 8); \ } \ +\ + void printdec(uint value) \ + { \ + if (value > 10) { \ + printdec(value / 10); \ + value %= 10; \ + } else if (value == 10) { \ + _debug_uart_putc('1'); \ + value = 0; \ + } \ + _debug_uart_putc('0' + value); \ + } \ \ void debug_uart_init(void) \ { \

On 2019/7/16 上午2:28, Jagan Teki wrote:
Add printdec, this would help to print an output a decimalism value.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
include/debug_uart.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/include/debug_uart.h b/include/debug_uart.h index 34e8b2fc81..cd70ae1a04 100644 --- a/include/debug_uart.h +++ b/include/debug_uart.h @@ -104,6 +104,13 @@ void printhex4(uint value); */ void printhex8(uint value);
+/**
- printdec() - Output a decimalism value
- @value: Value to output
- */
+void printdec(uint value);
- #ifdef CONFIG_DEBUG_UART_ANNOUNCE #define _DEBUG_UART_ANNOUNCE printascii("<debug_uart> "); #else
@@ -170,6 +177,18 @@ void printhex8(uint value); { \ printhex(value, 8); \ } \ +\
- void printdec(uint value) \
- { \
if (value > 10) { \
printdec(value / 10); \
value %= 10; \
} else if (value == 10) { \
_debug_uart_putc('1'); \
value = 0; \
} \
_debug_uart_putc('0' + value); \
- } \ \ void debug_uart_init(void) \ { \

Add sdram driver to handle debug across rockchip SoCs.
This would help to improve code debugging feature for sdram drivers in rockchip family, whoever wants to debug the driver should call these core debug code on their respective platform sdram drivers.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com --- .../include/asm/arch-rockchip/sdram_common.h | 9 +++++ drivers/ram/rockchip/Kconfig | 9 +++++ drivers/ram/rockchip/Makefile | 1 + drivers/ram/rockchip/sdram_debug.c | 34 +++++++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 drivers/ram/rockchip/sdram_debug.c
diff --git a/arch/arm/include/asm/arch-rockchip/sdram_common.h b/arch/arm/include/asm/arch-rockchip/sdram_common.h index 7ac25af327..171b233f95 100644 --- a/arch/arm/include/asm/arch-rockchip/sdram_common.h +++ b/arch/arm/include/asm/arch-rockchip/sdram_common.h @@ -92,4 +92,13 @@ size_t rockchip_sdram_size(phys_addr_t reg);
/* Called by U-Boot board_init_r for Rockchip SoCs */ int dram_init(void); + +#if !defined(CONFIG_RAM_ROCKCHIP_DEBUG) +inline void sdram_print_dram_type(unsigned char dramtype) +{ +} +#else +void sdram_print_dram_type(unsigned char dramtype); +#endif /* CONFIG_RAM_ROCKCHIP_DEBUG */ + #endif diff --git a/drivers/ram/rockchip/Kconfig b/drivers/ram/rockchip/Kconfig index 995cb487b8..151ffb684d 100644 --- a/drivers/ram/rockchip/Kconfig +++ b/drivers/ram/rockchip/Kconfig @@ -7,6 +7,15 @@ config RAM_ROCKCHIP
if RAM_ROCKCHIP
+config RAM_ROCKCHIP_DEBUG + bool "Rockchip ram drivers debugging" + help + This enables debugging ram driver API's for the platforms + based on Rockchip SoCs. + + This is an option for developers to understand the ram drivers + initialization, configurations and etc. + config RAM_RK3399 bool "Ram driver for Rockchip RK3399" default ROCKCHIP_RK3399 diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile index 07d4b62a9d..feb1f82d00 100644 --- a/drivers/ram/rockchip/Makefile +++ b/drivers/ram/rockchip/Makefile @@ -3,6 +3,7 @@ # Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH #
+obj-$(CONFIG_RAM_ROCKCHIP_DEBUG) += sdram_debug.o obj-$(CONFIG_ROCKCHIP_RK3368) = dmc-rk3368.o obj-$(CONFIG_ROCKCHIP_RK3128) = sdram_rk3128.o obj-$(CONFIG_ROCKCHIP_RK3188) = sdram_rk3188.o diff --git a/drivers/ram/rockchip/sdram_debug.c b/drivers/ram/rockchip/sdram_debug.c new file mode 100644 index 0000000000..c13e140fa5 --- /dev/null +++ b/drivers/ram/rockchip/sdram_debug.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * (C) Copyright 2019 Rockchip Electronics Co., Ltd + * (C) Copyright 2019 Amarula Solutions. + * Author: Jagan Teki jagan@amarulasolutions.com + */ + +#include <common.h> +#include <debug_uart.h> +#include <asm/arch-rockchip/sdram_common.h> + +void sdram_print_dram_type(unsigned char dramtype) +{ + switch (dramtype) { + case DDR3: + printascii("DDR3"); + break; + case DDR4: + printascii("DDR4"); + break; + case LPDDR2: + printascii("LPDDR2"); + break; + case LPDDR3: + printascii("LPDDR3"); + break; + case LPDDR4: + printascii("LPDDR4"); + break; + default: + printascii("Unknown Device"); + break; + } +}

On 2019/7/16 上午2:28, Jagan Teki wrote:
Add sdram driver to handle debug across rockchip SoCs.
This would help to improve code debugging feature for sdram drivers in rockchip family, whoever wants to debug the driver should call these core debug code on their respective platform sdram drivers.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
.../include/asm/arch-rockchip/sdram_common.h | 9 +++++ drivers/ram/rockchip/Kconfig | 9 +++++ drivers/ram/rockchip/Makefile | 1 + drivers/ram/rockchip/sdram_debug.c | 34 +++++++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 drivers/ram/rockchip/sdram_debug.c
diff --git a/arch/arm/include/asm/arch-rockchip/sdram_common.h b/arch/arm/include/asm/arch-rockchip/sdram_common.h index 7ac25af327..171b233f95 100644 --- a/arch/arm/include/asm/arch-rockchip/sdram_common.h +++ b/arch/arm/include/asm/arch-rockchip/sdram_common.h @@ -92,4 +92,13 @@ size_t rockchip_sdram_size(phys_addr_t reg);
/* Called by U-Boot board_init_r for Rockchip SoCs */ int dram_init(void);
+#if !defined(CONFIG_RAM_ROCKCHIP_DEBUG) +inline void sdram_print_dram_type(unsigned char dramtype) +{ +} +#else +void sdram_print_dram_type(unsigned char dramtype); +#endif /* CONFIG_RAM_ROCKCHIP_DEBUG */
- #endif
diff --git a/drivers/ram/rockchip/Kconfig b/drivers/ram/rockchip/Kconfig index 995cb487b8..151ffb684d 100644 --- a/drivers/ram/rockchip/Kconfig +++ b/drivers/ram/rockchip/Kconfig @@ -7,6 +7,15 @@ config RAM_ROCKCHIP
if RAM_ROCKCHIP
+config RAM_ROCKCHIP_DEBUG
- bool "Rockchip ram drivers debugging"
- help
This enables debugging ram driver API's for the platforms
based on Rockchip SoCs.
This is an option for developers to understand the ram drivers
initialization, configurations and etc.
- config RAM_RK3399 bool "Ram driver for Rockchip RK3399" default ROCKCHIP_RK3399
diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile index 07d4b62a9d..feb1f82d00 100644 --- a/drivers/ram/rockchip/Makefile +++ b/drivers/ram/rockchip/Makefile @@ -3,6 +3,7 @@ # Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH #
+obj-$(CONFIG_RAM_ROCKCHIP_DEBUG) += sdram_debug.o obj-$(CONFIG_ROCKCHIP_RK3368) = dmc-rk3368.o obj-$(CONFIG_ROCKCHIP_RK3128) = sdram_rk3128.o obj-$(CONFIG_ROCKCHIP_RK3188) = sdram_rk3188.o diff --git a/drivers/ram/rockchip/sdram_debug.c b/drivers/ram/rockchip/sdram_debug.c new file mode 100644 index 0000000000..c13e140fa5 --- /dev/null +++ b/drivers/ram/rockchip/sdram_debug.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/*
- (C) Copyright 2019 Rockchip Electronics Co., Ltd
- (C) Copyright 2019 Amarula Solutions.
- Author: Jagan Teki jagan@amarulasolutions.com
- */
+#include <common.h> +#include <debug_uart.h> +#include <asm/arch-rockchip/sdram_common.h>
+void sdram_print_dram_type(unsigned char dramtype) +{
- switch (dramtype) {
- case DDR3:
printascii("DDR3");
break;
- case DDR4:
printascii("DDR4");
break;
- case LPDDR2:
printascii("LPDDR2");
break;
- case LPDDR3:
printascii("LPDDR3");
break;
- case LPDDR4:
printascii("LPDDR4");
break;
- default:
printascii("Unknown Device");
break;
- }
+}

Add sdram ddr info print support, this would help to observe the sdram base parameters.
Here is sample print on LPDDR4, 50MHz channel 0 BW=32 Col=10 Bk=8 CS0 Row=15 CS1 Row=15 CS=2 Die BW=16
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com --- .../include/asm/arch-rockchip/sdram_common.h | 7 ++++ drivers/ram/rockchip/sdram_debug.c | 40 +++++++++++++++++++ 2 files changed, 47 insertions(+)
diff --git a/arch/arm/include/asm/arch-rockchip/sdram_common.h b/arch/arm/include/asm/arch-rockchip/sdram_common.h index 171b233f95..cfbb511843 100644 --- a/arch/arm/include/asm/arch-rockchip/sdram_common.h +++ b/arch/arm/include/asm/arch-rockchip/sdram_common.h @@ -97,8 +97,15 @@ int dram_init(void); inline void sdram_print_dram_type(unsigned char dramtype) { } + +inline void sdram_print_ddr_info(struct sdram_cap_info *cap_info, + struct sdram_base_params *base) +{ +} #else void sdram_print_dram_type(unsigned char dramtype); +void sdram_print_ddr_info(struct sdram_cap_info *cap_info, + struct sdram_base_params *base); #endif /* CONFIG_RAM_ROCKCHIP_DEBUG */
#endif diff --git a/drivers/ram/rockchip/sdram_debug.c b/drivers/ram/rockchip/sdram_debug.c index c13e140fa5..69a6f94a73 100644 --- a/drivers/ram/rockchip/sdram_debug.c +++ b/drivers/ram/rockchip/sdram_debug.c @@ -32,3 +32,43 @@ void sdram_print_dram_type(unsigned char dramtype) break; } } + +void sdram_print_ddr_info(struct sdram_cap_info *cap_info, + struct sdram_base_params *base) +{ + u32 bg; + + bg = (cap_info->dbw == 0) ? 2 : 1; + + sdram_print_dram_type(base->dramtype); + + printascii(", "); + printdec(base->ddr_freq); + printascii("MHz\n"); + + printascii("BW="); + printdec(8 << cap_info->bw); + + printascii(" Col="); + printdec(cap_info->col); + + printascii(" Bk="); + printdec(0x1 << cap_info->bk); + if (base->dramtype == DDR4) { + printascii(" BG="); + printdec(1 << bg); + } + + printascii(" CS0 Row="); + printdec(cap_info->cs0_row); + if (cap_info->rank > 1) { + printascii(" CS1 Row="); + printdec(cap_info->cs1_row); + } + + printascii(" CS="); + printdec(cap_info->rank); + + printascii(" Die BW="); + printdec(8 << cap_info->dbw); +}

On 2019/7/16 上午2:28, Jagan Teki wrote:
Add sdram ddr info print support, this would help to observe the sdram base parameters.
Here is sample print on LPDDR4, 50MHz channel 0 BW=32 Col=10 Bk=8 CS0 Row=15 CS1 Row=15 CS=2 Die BW=16
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
.../include/asm/arch-rockchip/sdram_common.h | 7 ++++ drivers/ram/rockchip/sdram_debug.c | 40 +++++++++++++++++++ 2 files changed, 47 insertions(+)
diff --git a/arch/arm/include/asm/arch-rockchip/sdram_common.h b/arch/arm/include/asm/arch-rockchip/sdram_common.h index 171b233f95..cfbb511843 100644 --- a/arch/arm/include/asm/arch-rockchip/sdram_common.h +++ b/arch/arm/include/asm/arch-rockchip/sdram_common.h @@ -97,8 +97,15 @@ int dram_init(void); inline void sdram_print_dram_type(unsigned char dramtype) { }
+inline void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
struct sdram_base_params *base)
+{ +} #else void sdram_print_dram_type(unsigned char dramtype); +void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
struct sdram_base_params *base);
#endif /* CONFIG_RAM_ROCKCHIP_DEBUG */
#endif
diff --git a/drivers/ram/rockchip/sdram_debug.c b/drivers/ram/rockchip/sdram_debug.c index c13e140fa5..69a6f94a73 100644 --- a/drivers/ram/rockchip/sdram_debug.c +++ b/drivers/ram/rockchip/sdram_debug.c @@ -32,3 +32,43 @@ void sdram_print_dram_type(unsigned char dramtype) break; } }
+void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
struct sdram_base_params *base)
+{
- u32 bg;
- bg = (cap_info->dbw == 0) ? 2 : 1;
- sdram_print_dram_type(base->dramtype);
- printascii(", ");
- printdec(base->ddr_freq);
- printascii("MHz\n");
- printascii("BW=");
- printdec(8 << cap_info->bw);
- printascii(" Col=");
- printdec(cap_info->col);
- printascii(" Bk=");
- printdec(0x1 << cap_info->bk);
- if (base->dramtype == DDR4) {
printascii(" BG=");
printdec(1 << bg);
- }
- printascii(" CS0 Row=");
- printdec(cap_info->cs0_row);
- if (cap_info->rank > 1) {
printascii(" CS1 Row=");
printdec(cap_info->cs1_row);
- }
- printascii(" CS=");
- printdec(cap_info->rank);
- printascii(" Die BW=");
- printdec(8 << cap_info->dbw);
+}

Add code to get the channel capacity, this would help to print the capacity of specific channel.
Here is sample print on LPDDR4, 50MHz channel 0 BW=32 Col=10 Bk=8 CS0 Row=15 CS1 Row=15 CS=2 Die BW=16 Size=2048MB
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com --- drivers/ram/rockchip/sdram_debug.c | 46 +++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-)
diff --git a/drivers/ram/rockchip/sdram_debug.c b/drivers/ram/rockchip/sdram_debug.c index 69a6f94a73..19e9225c12 100644 --- a/drivers/ram/rockchip/sdram_debug.c +++ b/drivers/ram/rockchip/sdram_debug.c @@ -33,10 +33,46 @@ void sdram_print_dram_type(unsigned char dramtype) } }
+/** + * cs = 0, cs0 + * cs = 1, cs1 + * cs => 2, cs0+cs1 + * note: it didn't consider about row_3_4 + */ +u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type) +{ + u32 bg; + u64 cap[2]; + + if (dram_type == DDR4) + /* DDR4 8bit dram BG = 2(4bank groups), + * 16bit dram BG = 1 (2 bank groups) + */ + bg = (cap_info->dbw == 0) ? 2 : 1; + else + bg = 0; + + cap[0] = 1llu << (cap_info->bw + cap_info->col + + bg + cap_info->bk + cap_info->cs0_row); + + if (cap_info->rank == 2) + cap[1] = 1llu << (cap_info->bw + cap_info->col + + bg + cap_info->bk + cap_info->cs1_row); + else + cap[1] = 0; + + if (cs == 0) + return cap[0]; + else if (cs == 1) + return cap[1]; + else + return (cap[0] + cap[1]); +} + void sdram_print_ddr_info(struct sdram_cap_info *cap_info, struct sdram_base_params *base) { - u32 bg; + u32 bg, cap;
bg = (cap_info->dbw == 0) ? 2 : 1;
@@ -71,4 +107,12 @@ void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
printascii(" Die BW="); printdec(8 << cap_info->dbw); + + cap = sdram_get_cs_cap(cap_info, 3, base->dramtype); + if (cap_info->row_3_4) + cap = cap * 3 / 4; + + printascii(" Size="); + printdec(cap >> 20); + printascii("MB\n"); }

On 2019/7/16 上午2:28, Jagan Teki wrote:
Add code to get the channel capacity, this would help to print the capacity of specific channel.
Here is sample print on LPDDR4, 50MHz channel 0 BW=32 Col=10 Bk=8 CS0 Row=15 CS1 Row=15 CS=2 Die BW=16 Size=2048MB
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
drivers/ram/rockchip/sdram_debug.c | 46 +++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-)
diff --git a/drivers/ram/rockchip/sdram_debug.c b/drivers/ram/rockchip/sdram_debug.c index 69a6f94a73..19e9225c12 100644 --- a/drivers/ram/rockchip/sdram_debug.c +++ b/drivers/ram/rockchip/sdram_debug.c @@ -33,10 +33,46 @@ void sdram_print_dram_type(unsigned char dramtype) } }
+/**
- cs = 0, cs0
- cs = 1, cs1
- cs => 2, cs0+cs1
- note: it didn't consider about row_3_4
- */
+u64 sdram_get_cs_cap(struct sdram_cap_info *cap_info, u32 cs, u32 dram_type) +{
- u32 bg;
- u64 cap[2];
- if (dram_type == DDR4)
/* DDR4 8bit dram BG = 2(4bank groups),
* 16bit dram BG = 1 (2 bank groups)
*/
bg = (cap_info->dbw == 0) ? 2 : 1;
- else
bg = 0;
- cap[0] = 1llu << (cap_info->bw + cap_info->col +
bg + cap_info->bk + cap_info->cs0_row);
- if (cap_info->rank == 2)
cap[1] = 1llu << (cap_info->bw + cap_info->col +
bg + cap_info->bk + cap_info->cs1_row);
- else
cap[1] = 0;
- if (cs == 0)
return cap[0];
- else if (cs == 1)
return cap[1];
- else
return (cap[0] + cap[1]);
+}
- void sdram_print_ddr_info(struct sdram_cap_info *cap_info, struct sdram_base_params *base) {
- u32 bg;
u32 bg, cap;
bg = (cap_info->dbw == 0) ? 2 : 1;
@@ -71,4 +107,12 @@ void sdram_print_ddr_info(struct sdram_cap_info *cap_info,
printascii(" Die BW="); printdec(8 << cap_info->dbw);
- cap = sdram_get_cs_cap(cap_info, 3, base->dramtype);
- if (cap_info->row_3_4)
cap = cap * 3 / 4;
- printascii(" Size=");
- printdec(cap >> 20);
- printascii("MB\n"); }

Add code to print the channel stride, this would help to print the stride of associated channel.
Here is sample print on LPDDR4, 50MHz. 256B stride
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com --- .../include/asm/arch-rockchip/sdram_common.h | 5 ++++ drivers/ram/rockchip/sdram_debug.c | 29 +++++++++++++++++++ 2 files changed, 34 insertions(+)
diff --git a/arch/arm/include/asm/arch-rockchip/sdram_common.h b/arch/arm/include/asm/arch-rockchip/sdram_common.h index cfbb511843..b7549f5d8a 100644 --- a/arch/arm/include/asm/arch-rockchip/sdram_common.h +++ b/arch/arm/include/asm/arch-rockchip/sdram_common.h @@ -102,10 +102,15 @@ inline void sdram_print_ddr_info(struct sdram_cap_info *cap_info, struct sdram_base_params *base) { } + +inline void sdram_print_stride(unsigned int stride) +{ +} #else void sdram_print_dram_type(unsigned char dramtype); void sdram_print_ddr_info(struct sdram_cap_info *cap_info, struct sdram_base_params *base); +void sdram_print_stride(unsigned int stride); #endif /* CONFIG_RAM_ROCKCHIP_DEBUG */
#endif diff --git a/drivers/ram/rockchip/sdram_debug.c b/drivers/ram/rockchip/sdram_debug.c index 19e9225c12..9cf662675b 100644 --- a/drivers/ram/rockchip/sdram_debug.c +++ b/drivers/ram/rockchip/sdram_debug.c @@ -116,3 +116,32 @@ void sdram_print_ddr_info(struct sdram_cap_info *cap_info, printdec(cap >> 20); printascii("MB\n"); } + +void sdram_print_stride(unsigned int stride) +{ + switch (stride) { + case 0xc: + printf("128B stride\n"); + break; + case 5: + case 9: + case 0xd: + case 0x11: + case 0x19: + printf("256B stride\n"); + break; + case 0xa: + case 0xe: + case 0x12: + printf("512B stride\n"); + break; + case 0xf: + printf("4K stride\n"); + break; + case 0x1f: + printf("32MB + 256B stride\n"); + break; + default: + printf("no stride\n"); + } +}

On 2019/7/16 上午2:28, Jagan Teki wrote:
Add code to print the channel stride, this would help to print the stride of associated channel.
Here is sample print on LPDDR4, 50MHz. 256B stride
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
.../include/asm/arch-rockchip/sdram_common.h | 5 ++++ drivers/ram/rockchip/sdram_debug.c | 29 +++++++++++++++++++ 2 files changed, 34 insertions(+)
diff --git a/arch/arm/include/asm/arch-rockchip/sdram_common.h b/arch/arm/include/asm/arch-rockchip/sdram_common.h index cfbb511843..b7549f5d8a 100644 --- a/arch/arm/include/asm/arch-rockchip/sdram_common.h +++ b/arch/arm/include/asm/arch-rockchip/sdram_common.h @@ -102,10 +102,15 @@ inline void sdram_print_ddr_info(struct sdram_cap_info *cap_info, struct sdram_base_params *base) { }
+inline void sdram_print_stride(unsigned int stride) +{ +} #else void sdram_print_dram_type(unsigned char dramtype); void sdram_print_ddr_info(struct sdram_cap_info *cap_info, struct sdram_base_params *base); +void sdram_print_stride(unsigned int stride); #endif /* CONFIG_RAM_ROCKCHIP_DEBUG */
#endif diff --git a/drivers/ram/rockchip/sdram_debug.c b/drivers/ram/rockchip/sdram_debug.c index 19e9225c12..9cf662675b 100644 --- a/drivers/ram/rockchip/sdram_debug.c +++ b/drivers/ram/rockchip/sdram_debug.c @@ -116,3 +116,32 @@ void sdram_print_ddr_info(struct sdram_cap_info *cap_info, printdec(cap >> 20); printascii("MB\n"); }
+void sdram_print_stride(unsigned int stride) +{
- switch (stride) {
- case 0xc:
printf("128B stride\n");
break;
- case 5:
- case 9:
- case 0xd:
- case 0x11:
- case 0x19:
printf("256B stride\n");
break;
- case 0xa:
- case 0xe:
- case 0x12:
printf("512B stride\n");
break;
- case 0xf:
printf("4K stride\n");
break;
- case 0x1f:
printf("32MB + 256B stride\n");
break;
- default:
printf("no stride\n");
- }
+}

stride value from sdram timings can be computed dynamically based on the determined capacity for the given channel.
Right now these stride values are taken as part of sdram timings via dtsi, but it possible to use same timings dtsi for given frequency even though the configured board sdram do support single channel with different size by dynamically detect the stride value.
Example, NanoPi NEO4 do have DDR3-1866, but with single channel and 1GB size with dynamic stride detection it is possible to use existing rk3399-sdram-ddr3-1866.dtsi whose stride, number of channels and capacity it support is d efferent.
So, add initial support to calculate the stride value for 2 channels sdram, which is available by default on existing boards.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com --- drivers/ram/rockchip/sdram_rk3399.c | 71 ++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 084c949728..c626ef602c 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -1183,8 +1183,75 @@ static int switch_to_phy_index1(struct dram_info *dram, return 0; }
+static unsigned char calculate_stride(struct rk3399_sdram_params *params) +{ + unsigned int stride = params->base.stride; + unsigned int channel, chinfo = 0; + unsigned int ch_cap[2] = {0, 0}; + u64 cap; + + for (channel = 0; channel < 2; channel++) { + unsigned int cs0_cap = 0; + unsigned int cs1_cap = 0; + struct sdram_cap_info *cap_info = ¶ms->ch[channel].cap_info; + + if (cap_info->col == 0) + continue; + + cs0_cap = (1 << (cap_info->cs0_row + cap_info->col + + cap_info->bk + cap_info->bw - 20)); + if (cap_info->rank > 1) + cs1_cap = cs0_cap >> (cap_info->cs0_row + - cap_info->cs1_row); + if (cap_info->row_3_4) { + cs0_cap = cs0_cap * 3 / 4; + cs1_cap = cs1_cap * 3 / 4; + } + ch_cap[channel] = cs0_cap + cs1_cap; + chinfo |= 1 << channel; + } + + /* stride calculation for 2 channels, default gstride type is 256B */ + if (ch_cap[0] == ch_cap[1]) { + cap = ch_cap[0] + ch_cap[1]; + switch (cap) { + /* 512MB */ + case 512: + stride = 0; + break; + /* 1GB */ + case 1024: + stride = 0x5; + break; + /* + * 768MB + 768MB same as total 2GB memory + * useful space: 0-768MB 1GB-1792MB + */ + case 1536: + /* 2GB */ + case 2048: + stride = 0x9; + break; + /* 1536MB + 1536MB */ + case 3072: + stride = 0x11; + break; + /* 4GB */ + case 4096: + stride = 0xD; + break; + default: + printf("%s: Unable to calculate stride for ", __func__); + print_size((cap * (1 << 20)), " capacity\n"); + break; + } + } + + return stride; +} + static int sdram_init(struct dram_info *dram, - const struct rk3399_sdram_params *params) + struct rk3399_sdram_params *params) { unsigned char dramtype = params->base.dramtype; unsigned int ddr_freq = params->base.ddr_freq; @@ -1232,6 +1299,8 @@ static int sdram_init(struct dram_info *dram, set_ddrconfig(chan, params, channel, params->ch[channel].cap_info.ddrconfig); } + + params->base.stride = calculate_stride(params); dram_all_config(dram, params); switch_to_phy_index1(dram, params);

On 2019/7/16 上午2:28, Jagan Teki wrote:
stride value from sdram timings can be computed dynamically based on the determined capacity for the given channel.
Right now these stride values are taken as part of sdram timings via dtsi, but it possible to use same timings dtsi for given frequency even though the configured board sdram do support single channel with different size by dynamically detect the stride value.
Example, NanoPi NEO4 do have DDR3-1866, but with single channel and 1GB size with dynamic stride detection it is possible to use existing rk3399-sdram-ddr3-1866.dtsi whose stride, number of channels and capacity it support is d efferent.
So, add initial support to calculate the stride value for 2 channels sdram, which is available by default on existing boards.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
drivers/ram/rockchip/sdram_rk3399.c | 71 ++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 084c949728..c626ef602c 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -1183,8 +1183,75 @@ static int switch_to_phy_index1(struct dram_info *dram, return 0; }
+static unsigned char calculate_stride(struct rk3399_sdram_params *params) +{
- unsigned int stride = params->base.stride;
- unsigned int channel, chinfo = 0;
- unsigned int ch_cap[2] = {0, 0};
- u64 cap;
- for (channel = 0; channel < 2; channel++) {
unsigned int cs0_cap = 0;
unsigned int cs1_cap = 0;
struct sdram_cap_info *cap_info = ¶ms->ch[channel].cap_info;
if (cap_info->col == 0)
continue;
cs0_cap = (1 << (cap_info->cs0_row + cap_info->col +
cap_info->bk + cap_info->bw - 20));
if (cap_info->rank > 1)
cs1_cap = cs0_cap >> (cap_info->cs0_row
- cap_info->cs1_row);
if (cap_info->row_3_4) {
cs0_cap = cs0_cap * 3 / 4;
cs1_cap = cs1_cap * 3 / 4;
}
ch_cap[channel] = cs0_cap + cs1_cap;
chinfo |= 1 << channel;
- }
- /* stride calculation for 2 channels, default gstride type is 256B */
- if (ch_cap[0] == ch_cap[1]) {
cap = ch_cap[0] + ch_cap[1];
switch (cap) {
/* 512MB */
case 512:
stride = 0;
break;
/* 1GB */
case 1024:
stride = 0x5;
break;
/*
* 768MB + 768MB same as total 2GB memory
* useful space: 0-768MB 1GB-1792MB
*/
case 1536:
/* 2GB */
case 2048:
stride = 0x9;
break;
/* 1536MB + 1536MB */
case 3072:
stride = 0x11;
break;
/* 4GB */
case 4096:
stride = 0xD;
break;
default:
printf("%s: Unable to calculate stride for ", __func__);
print_size((cap * (1 << 20)), " capacity\n");
break;
}
- }
- return stride;
+}
- static int sdram_init(struct dram_info *dram,
const struct rk3399_sdram_params *params)
{ unsigned char dramtype = params->base.dramtype; unsigned int ddr_freq = params->base.ddr_freq;struct rk3399_sdram_params *params)
@@ -1232,6 +1299,8 @@ static int sdram_init(struct dram_info *dram, set_ddrconfig(chan, params, channel, params->ch[channel].cap_info.ddrconfig); }
- params->base.stride = calculate_stride(params); dram_all_config(dram, params); switch_to_phy_index1(dram, params);

Add stride computation for the sdram which support single channel a
This configuration available in NanoPi NEO4 and the same can work with existing rk3399-sdram-ddr3-1866.dtsi
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com --- drivers/ram/rockchip/sdram_rk3399.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index c626ef602c..8bbacb5275 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -1211,6 +1211,10 @@ static unsigned char calculate_stride(struct rk3399_sdram_params *params) chinfo |= 1 << channel; }
+ /* stride calculation for 1 channel */ + if (params->base.num_channels == 1 && chinfo & 1) + return 0x17; /* channel a */ + /* stride calculation for 2 channels, default gstride type is 256B */ if (ch_cap[0] == ch_cap[1]) { cap = ch_cap[0] + ch_cap[1];

On 2019/7/16 上午2:28, Jagan Teki wrote:
Add stride computation for the sdram which support single channel a
This configuration available in NanoPi NEO4 and the same can work with existing rk3399-sdram-ddr3-1866.dtsi
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
drivers/ram/rockchip/sdram_rk3399.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index c626ef602c..8bbacb5275 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -1211,6 +1211,10 @@ static unsigned char calculate_stride(struct rk3399_sdram_params *params) chinfo |= 1 << channel; }
- /* stride calculation for 1 channel */
- if (params->base.num_channels == 1 && chinfo & 1)
return 0x17; /* channel a */
- /* stride calculation for 2 channels, default gstride type is 256B */ if (ch_cap[0] == ch_cap[1]) { cap = ch_cap[0] + ch_cap[1];

Right now the rk3399 sdram driver assume that the board has configured with 2 channels, so any possibility to enable single channel on the same driver will encounter channel #1 data training failure.
Log: U-Boot TPL board init sdram_init: data training failed rk3399_dmc_init DRAM init failed -5
So, add an algorithm that can capable to compute the active or configured rank with associated channel like a) do rank loop to compute the active rank, with associated channel numbers b) then, succeed the data training only for configured channel c) preserve the rank for given channel d) do channel loop for setting the active channel e) if given rank is zero or inactive on the specific channel, clear the timings for the associated channel f) finally, return error if number of channels is zero
Tested in NanoPI-NEO4 since it support single channel sdram configuration.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com --- drivers/ram/rockchip/sdram_rk3399.c | 110 ++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 24 deletions(-)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 8bbacb5275..b83955f94e 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -1254,13 +1254,52 @@ static unsigned char calculate_stride(struct rk3399_sdram_params *params) return stride; }
+static void clear_channel_params(struct rk3399_sdram_params *params, u8 channel) +{ + params->ch[channel].cap_info.rank = 0; + params->ch[channel].cap_info.col = 0; + params->ch[channel].cap_info.bk = 0; + params->ch[channel].cap_info.bw = 32; + params->ch[channel].cap_info.dbw = 32; + params->ch[channel].cap_info.row_3_4 = 0; + params->ch[channel].cap_info.cs0_row = 0; + params->ch[channel].cap_info.cs1_row = 0; + params->ch[channel].cap_info.ddrconfig = 0; +} + +static int pctl_init(struct dram_info *dram, struct rk3399_sdram_params *params) +{ + int channel; + int ret; + + for (channel = 0; channel < 2; channel++) { + const struct chan_info *chan = &dram->chan[channel]; + struct rk3399_cru *cru = dram->cru; + struct rk3399_ddr_publ_regs *publ = chan->publ; + + phy_pctrl_reset(cru, channel); + phy_dll_bypass_set(publ, params->base.ddr_freq); + + ret = pctl_cfg(dram, chan, channel, params); + if (ret < 0) { + printf("%s: pctl config failed\n", __func__); + return ret; + } + + /* start to trigger initialization */ + pctl_start(dram, channel); + } + + return 0; +} + static int sdram_init(struct dram_info *dram, struct rk3399_sdram_params *params) { unsigned char dramtype = params->base.dramtype; unsigned int ddr_freq = params->base.ddr_freq; - struct rk3399_cru *cru = dram->cru; - int channel; + u32 training_flag = PI_READ_GATE_TRAINING; + int channel, ch, rank; int ret;
debug("Starting SDRAM initialization...\n"); @@ -1272,36 +1311,59 @@ static int sdram_init(struct dram_info *dram, return -E2BIG; }
- for (channel = 0; channel < 2; channel++) { - const struct chan_info *chan = &dram->chan[channel]; - struct rk3399_ddr_publ_regs *publ = chan->publ; + for (ch = 0; ch < 2; ch++) { + params->ch[ch].cap_info.rank = 2; + for (rank = 2; rank != 0; rank--) { + ret = pctl_init(dram, params); + if (ret < 0) { + printf("%s: pctl init failed\n", __func__); + return ret; + }
- phy_pctrl_reset(cru, channel); - phy_dll_bypass_set(publ, ddr_freq); + /* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */ + if (dramtype == LPDDR3) + udelay(10);
- if (channel >= params->base.num_channels) - continue; + params->ch[ch].cap_info.rank = rank;
- ret = pctl_cfg(dram, chan, channel, params); - if (ret < 0) { - printf("%s: pctl config failed\n", __func__); - return ret; - } + /* + * LPDDR3 CA training msut be trigger before + * other training. + * DDR3 is not have CA training. + */ + if (params->base.dramtype == LPDDR3) + training_flag |= PI_CA_TRAINING;
- /* start to trigger initialization */ - pctl_start(dram, channel); + if (!(data_training(&dram->chan[ch], ch, + params, training_flag))) + break; + } + /* Computed rank with associated channel number */ + params->ch[ch].cap_info.rank = rank; + }
- /* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */ - if (dramtype == LPDDR3) - udelay(10); + params->base.num_channels = 0; + for (channel = 0; channel < 2; channel++) { + const struct chan_info *chan = &dram->chan[channel]; + struct sdram_cap_info *cap_info = ¶ms->ch[channel].cap_info;
- if (data_training(chan, channel, params, PI_FULL_TRAINING)) { - printf("%s: data training failed\n", __func__); - return -EIO; + if (cap_info->rank == 0) { + clear_channel_params(params, channel); + continue; + } else { + params->base.num_channels++; }
- set_ddrconfig(chan, params, channel, - params->ch[channel].cap_info.ddrconfig); + debug("Channel "); + debug(channel ? "1: " : "0: "); + + set_ddrconfig(chan, params, channel, cap_info->ddrconfig); + } + + if (params->base.num_channels == 0) { + printf("%s: ", __func__); + printf(" - %dMHz failed!\n", params->base.ddr_freq); + return -EINVAL; }
params->base.stride = calculate_stride(params);

On 2019/7/16 上午2:28, Jagan Teki wrote:
Right now the rk3399 sdram driver assume that the board has configured with 2 channels, so any possibility to enable single channel on the same driver will encounter channel #1 data training failure.
Log: U-Boot TPL board init sdram_init: data training failed rk3399_dmc_init DRAM init failed -5
So, add an algorithm that can capable to compute the active or configured rank with associated channel like a) do rank loop to compute the active rank, with associated channel numbers b) then, succeed the data training only for configured channel c) preserve the rank for given channel d) do channel loop for setting the active channel e) if given rank is zero or inactive on the specific channel, clear the timings for the associated channel f) finally, return error if number of channels is zero
Tested in NanoPI-NEO4 since it support single channel sdram configuration.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
drivers/ram/rockchip/sdram_rk3399.c | 110 ++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 24 deletions(-)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 8bbacb5275..b83955f94e 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -1254,13 +1254,52 @@ static unsigned char calculate_stride(struct rk3399_sdram_params *params) return stride; }
+static void clear_channel_params(struct rk3399_sdram_params *params, u8 channel) +{
- params->ch[channel].cap_info.rank = 0;
- params->ch[channel].cap_info.col = 0;
- params->ch[channel].cap_info.bk = 0;
- params->ch[channel].cap_info.bw = 32;
- params->ch[channel].cap_info.dbw = 32;
- params->ch[channel].cap_info.row_3_4 = 0;
- params->ch[channel].cap_info.cs0_row = 0;
- params->ch[channel].cap_info.cs1_row = 0;
- params->ch[channel].cap_info.ddrconfig = 0;
+}
+static int pctl_init(struct dram_info *dram, struct rk3399_sdram_params *params) +{
- int channel;
- int ret;
- for (channel = 0; channel < 2; channel++) {
const struct chan_info *chan = &dram->chan[channel];
struct rk3399_cru *cru = dram->cru;
struct rk3399_ddr_publ_regs *publ = chan->publ;
phy_pctrl_reset(cru, channel);
phy_dll_bypass_set(publ, params->base.ddr_freq);
ret = pctl_cfg(dram, chan, channel, params);
if (ret < 0) {
printf("%s: pctl config failed\n", __func__);
return ret;
}
/* start to trigger initialization */
pctl_start(dram, channel);
- }
- return 0;
+}
- static int sdram_init(struct dram_info *dram, struct rk3399_sdram_params *params) { unsigned char dramtype = params->base.dramtype; unsigned int ddr_freq = params->base.ddr_freq;
- struct rk3399_cru *cru = dram->cru;
- int channel;
u32 training_flag = PI_READ_GATE_TRAINING;
int channel, ch, rank; int ret;
debug("Starting SDRAM initialization...\n");
@@ -1272,36 +1311,59 @@ static int sdram_init(struct dram_info *dram, return -E2BIG; }
- for (channel = 0; channel < 2; channel++) {
const struct chan_info *chan = &dram->chan[channel];
struct rk3399_ddr_publ_regs *publ = chan->publ;
- for (ch = 0; ch < 2; ch++) {
params->ch[ch].cap_info.rank = 2;
for (rank = 2; rank != 0; rank--) {
ret = pctl_init(dram, params);
if (ret < 0) {
printf("%s: pctl init failed\n", __func__);
return ret;
}
phy_pctrl_reset(cru, channel);
phy_dll_bypass_set(publ, ddr_freq);
/* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
if (dramtype == LPDDR3)
udelay(10);
if (channel >= params->base.num_channels)
continue;
params->ch[ch].cap_info.rank = rank;
ret = pctl_cfg(dram, chan, channel, params);
if (ret < 0) {
printf("%s: pctl config failed\n", __func__);
return ret;
}
/*
* LPDDR3 CA training msut be trigger before
* other training.
* DDR3 is not have CA training.
*/
if (params->base.dramtype == LPDDR3)
training_flag |= PI_CA_TRAINING;
/* start to trigger initialization */
pctl_start(dram, channel);
if (!(data_training(&dram->chan[ch], ch,
params, training_flag)))
break;
}
/* Computed rank with associated channel number */
params->ch[ch].cap_info.rank = rank;
- }
/* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
if (dramtype == LPDDR3)
udelay(10);
- params->base.num_channels = 0;
- for (channel = 0; channel < 2; channel++) {
const struct chan_info *chan = &dram->chan[channel];
struct sdram_cap_info *cap_info = ¶ms->ch[channel].cap_info;
if (data_training(chan, channel, params, PI_FULL_TRAINING)) {
printf("%s: data training failed\n", __func__);
return -EIO;
if (cap_info->rank == 0) {
clear_channel_params(params, channel);
continue;
} else {
}params->base.num_channels++;
set_ddrconfig(chan, params, channel,
params->ch[channel].cap_info.ddrconfig);
debug("Channel ");
debug(channel ? "1: " : "0: ");
set_ddrconfig(chan, params, channel, cap_info->ddrconfig);
}
if (params->base.num_channels == 0) {
printf("%s: ", __func__);
printf(" - %dMHz failed!\n", params->base.ddr_freq);
return -EINVAL;
}
params->base.stride = calculate_stride(params);

Hi Jagan,
I'm sure this patch have some problem with evb-rk3399, which I think make the ddr not init correctly and error happen in ATF.
Please help to check the detail of this patch, you can send new version of this patch only to mailing list and I will replace it to older version.
Thanks, - Kever On 2019/7/16 上午2:28, Jagan Teki wrote:
Right now the rk3399 sdram driver assume that the board has configured with 2 channels, so any possibility to enable single channel on the same driver will encounter channel #1 data training failure.
Log: U-Boot TPL board init sdram_init: data training failed rk3399_dmc_init DRAM init failed -5
So, add an algorithm that can capable to compute the active or configured rank with associated channel like a) do rank loop to compute the active rank, with associated channel numbers b) then, succeed the data training only for configured channel c) preserve the rank for given channel d) do channel loop for setting the active channel e) if given rank is zero or inactive on the specific channel, clear the timings for the associated channel f) finally, return error if number of channels is zero
Tested in NanoPI-NEO4 since it support single channel sdram configuration.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com Signed-off-by: YouMin Chen cym@rock-chips.com
drivers/ram/rockchip/sdram_rk3399.c | 110 ++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 24 deletions(-)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 8bbacb5275..b83955f94e 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -1254,13 +1254,52 @@ static unsigned char calculate_stride(struct rk3399_sdram_params *params) return stride; }
+static void clear_channel_params(struct rk3399_sdram_params *params, u8 channel) +{
- params->ch[channel].cap_info.rank = 0;
- params->ch[channel].cap_info.col = 0;
- params->ch[channel].cap_info.bk = 0;
- params->ch[channel].cap_info.bw = 32;
- params->ch[channel].cap_info.dbw = 32;
- params->ch[channel].cap_info.row_3_4 = 0;
- params->ch[channel].cap_info.cs0_row = 0;
- params->ch[channel].cap_info.cs1_row = 0;
- params->ch[channel].cap_info.ddrconfig = 0;
+}
+static int pctl_init(struct dram_info *dram, struct rk3399_sdram_params *params) +{
- int channel;
- int ret;
- for (channel = 0; channel < 2; channel++) {
const struct chan_info *chan = &dram->chan[channel];
struct rk3399_cru *cru = dram->cru;
struct rk3399_ddr_publ_regs *publ = chan->publ;
phy_pctrl_reset(cru, channel);
phy_dll_bypass_set(publ, params->base.ddr_freq);
ret = pctl_cfg(dram, chan, channel, params);
if (ret < 0) {
printf("%s: pctl config failed\n", __func__);
return ret;
}
/* start to trigger initialization */
pctl_start(dram, channel);
- }
- return 0;
+}
- static int sdram_init(struct dram_info *dram, struct rk3399_sdram_params *params) { unsigned char dramtype = params->base.dramtype; unsigned int ddr_freq = params->base.ddr_freq;
- struct rk3399_cru *cru = dram->cru;
- int channel;
u32 training_flag = PI_READ_GATE_TRAINING;
int channel, ch, rank; int ret;
debug("Starting SDRAM initialization...\n");
@@ -1272,36 +1311,59 @@ static int sdram_init(struct dram_info *dram, return -E2BIG; }
- for (channel = 0; channel < 2; channel++) {
const struct chan_info *chan = &dram->chan[channel];
struct rk3399_ddr_publ_regs *publ = chan->publ;
- for (ch = 0; ch < 2; ch++) {
params->ch[ch].cap_info.rank = 2;
for (rank = 2; rank != 0; rank--) {
ret = pctl_init(dram, params);
if (ret < 0) {
printf("%s: pctl init failed\n", __func__);
return ret;
}
phy_pctrl_reset(cru, channel);
phy_dll_bypass_set(publ, ddr_freq);
/* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
if (dramtype == LPDDR3)
udelay(10);
if (channel >= params->base.num_channels)
continue;
params->ch[ch].cap_info.rank = rank;
ret = pctl_cfg(dram, chan, channel, params);
if (ret < 0) {
printf("%s: pctl config failed\n", __func__);
return ret;
}
/*
* LPDDR3 CA training msut be trigger before
* other training.
* DDR3 is not have CA training.
*/
if (params->base.dramtype == LPDDR3)
training_flag |= PI_CA_TRAINING;
/* start to trigger initialization */
pctl_start(dram, channel);
if (!(data_training(&dram->chan[ch], ch,
params, training_flag)))
break;
}
/* Computed rank with associated channel number */
params->ch[ch].cap_info.rank = rank;
- }
/* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
if (dramtype == LPDDR3)
udelay(10);
- params->base.num_channels = 0;
- for (channel = 0; channel < 2; channel++) {
const struct chan_info *chan = &dram->chan[channel];
struct sdram_cap_info *cap_info = ¶ms->ch[channel].cap_info;
if (data_training(chan, channel, params, PI_FULL_TRAINING)) {
printf("%s: data training failed\n", __func__);
return -EIO;
if (cap_info->rank == 0) {
clear_channel_params(params, channel);
continue;
} else {
}params->base.num_channels++;
set_ddrconfig(chan, params, channel,
params->ch[channel].cap_info.ddrconfig);
debug("Channel ");
debug(channel ? "1: " : "0: ");
set_ddrconfig(chan, params, channel, cap_info->ddrconfig);
}
if (params->base.num_channels == 0) {
printf("%s: ", __func__);
printf(" - %dMHz failed!\n", params->base.ddr_freq);
return -EINVAL;
}
params->base.stride = calculate_stride(params);

Hi Kever,
On Wed, Jul 17, 2019 at 6:23 PM Kever Yang kever.yang@rock-chips.com wrote:
Hi Jagan,
I'm sure this patch have some problem with evb-rk3399, which I
think make the ddr not init correctly and error happen in ATF.
Would you help to share the log for this. I made test on Nanopi-m4 which has same ddr type as evb, LPDDR3 and it booted fine with mainline ATF (with PLAT=rk3399 bl31). Below is the log details.
U-Boot TPL 2019.07-00145-gcb5756d9e2-dirty (Jul 18 2019 - 14:55:23) Channel 0: LPDDR3, 933MHz BW=32 Col=10 Bk=8 CS0 Row=15 CS1 Row=15 CS=2 Die BW=32 Size=2048MB Channel 1: LPDDR3, 933MHz BW=32 Col=10 Bk=8 CS0 Row=15 CS1 Row=15 CS=2 Die BW=32 Size=2048MB 256B stride Trying to boot from BOOTROM Returning to boot ROM...
U-Boot SPL 2019.07-00145-gcb5756d9e2-dirty (Jul 18 2019 - 14:55:23 +0530) Trying to boot from MMC1
U-Boot 2019.07-00145-gcb5756d9e2-dirty (Jul 18 2019 - 14:55:23 +0530)
Model: FriendlyElec NanoPi M4 DRAM: 3.9 GiB MMC: dwmmc@fe310000: 2, dwmmc@fe320000: 1, sdhci@fe330000: 0 Loading Environment from MMC... *** Warning - bad CRC, using default environment
In: serial@ff1a0000 Out: serial@ff1a0000 Err: serial@ff1a0000 Model: FriendlyElec NanoPi M4
Let me know if have anything to add?
Jagan.

This would help to debug the sdram base parameters while debugging existing chip or while supporting new sdram type.
It require explicit enablement of CONFIG_RAM_ROCKCHIP_DEBUG for showing the debug prints.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com --- drivers/ram/rockchip/sdram_rk3399.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index b83955f94e..9a60c24135 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -1251,6 +1251,8 @@ static unsigned char calculate_stride(struct rk3399_sdram_params *params) } }
+ sdram_print_stride(stride); + return stride; }
@@ -1357,11 +1359,14 @@ static int sdram_init(struct dram_info *dram, debug("Channel "); debug(channel ? "1: " : "0: ");
+ sdram_print_ddr_info(cap_info, ¶ms->base); + set_ddrconfig(chan, params, channel, cap_info->ddrconfig); }
if (params->base.num_channels == 0) { printf("%s: ", __func__); + sdram_print_dram_type(params->base.dramtype); printf(" - %dMHz failed!\n", params->base.ddr_freq); return -EINVAL; }

On 2019/7/16 上午2:28, Jagan Teki wrote:
This would help to debug the sdram base parameters while debugging existing chip or while supporting new sdram type.
It require explicit enablement of CONFIG_RAM_ROCKCHIP_DEBUG for showing the debug prints.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
drivers/ram/rockchip/sdram_rk3399.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index b83955f94e..9a60c24135 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -1251,6 +1251,8 @@ static unsigned char calculate_stride(struct rk3399_sdram_params *params) } }
- sdram_print_stride(stride);
- return stride; }
@@ -1357,11 +1359,14 @@ static int sdram_init(struct dram_info *dram, debug("Channel "); debug(channel ? "1: " : "0: ");
sdram_print_ddr_info(cap_info, ¶ms->base);
set_ddrconfig(chan, params, channel, cap_info->ddrconfig); }
if (params->base.num_channels == 0) { printf("%s: ", __func__);
sdram_print_dram_type(params->base.dramtype);
printf(" - %dMHz failed!\n", params->base.ddr_freq); return -EINVAL; }

Use DDR3-1866 2GB ddr timings dtsi for 1GB NanoPi Neo4 board.
Since sdram rk3399 support dynamic stride and rank detection it can able to detect 1GB ddr eventough the timings are meant for dual channel, 2GB size.
Bootchain after and before this change are:
TPL -> SPL -> U-Boot proper
rkbin -> SPL -> U-Boot proper
This certainly fix the second channel data training initialization since we have dynamic rank, stride where second channel capabilities are clear or memset to 0.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com --- arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi b/arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi index 7d22528f49..eb0aca4758 100644 --- a/arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi +++ b/arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi @@ -4,3 +4,4 @@ */
#include "rk3399-nanopi4-u-boot.dtsi" +#include "rk3399-sdram-ddr3-1866.dtsi"

On 2019/7/16 上午2:28, Jagan Teki wrote:
Use DDR3-1866 2GB ddr timings dtsi for 1GB NanoPi Neo4 board.
Since sdram rk3399 support dynamic stride and rank detection it can able to detect 1GB ddr eventough the timings are meant for dual channel, 2GB size.
Bootchain after and before this change are:
TPL -> SPL -> U-Boot proper
rkbin -> SPL -> U-Boot proper
This certainly fix the second channel data training initialization since we have dynamic rank, stride where second channel capabilities are clear or memset to 0.
Signed-off-by: Jagan Teki jagan@amarulasolutions.com
Reviewed-by: Kever Yang Kever.yang@rock-chips.com
Thanks, - Kever
arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi b/arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi index 7d22528f49..eb0aca4758 100644 --- a/arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi +++ b/arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi @@ -4,3 +4,4 @@ */
#include "rk3399-nanopi4-u-boot.dtsi" +#include "rk3399-sdram-ddr3-1866.dtsi"
participants (2)
-
Jagan Teki
-
Kever Yang