[U-Boot] [PATCH v3 16/18] ram: rk3399: Add rank detection support
Kever Yang
kever.yang at rock-chips.com
Tue Jul 16 07:45:17 UTC 2019
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 at amarulasolutions.com>
> Signed-off-by: YouMin Chen <cym at rock-chips.com>
Reviewed-by: Kever Yang <Kever.yang at 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);
More information about the U-Boot
mailing list