From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jagan Teki Subject: [PATCH 50/92] ram: rk3399: Add rank detection support Date: Tue, 11 Jun 2019 20:20:53 +0530 Message-ID: <20190611145135.21399-51-jagan@amarulasolutions.com> References: <20190611145135.21399-1-jagan@amarulasolutions.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <20190611145135.21399-1-jagan-dyjBcgdgk7Pe9wHmmfpqLFaTQe2KTcn/@public.gmane.org> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+glpar-linux-rockchip=m.gmane.org-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org To: Simon Glass , Philipp Tomsich , Kever Yang , YouMin Chen , u-boot-0aAXYlwwYIKGBzrmiIFOJg@public.gmane.org Cc: linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, linux-amarula-dyjBcgdgk7Pe9wHmmfpqLFaTQe2KTcn/@public.gmane.org, Jagan Teki , gajjar04akash-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org List-Id: linux-rockchip.vger.kernel.org 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 Signed-off-by: YouMin Chen --- drivers/ram/rockchip/sdram_rk3399.c | 112 +++++++++++++++++++++------- 1 file changed, 87 insertions(+), 25 deletions(-) diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 033b2730a6..b658d7d1ab 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -1257,13 +1257,52 @@ static unsigned char calculate_stride(struct rk3399_sdram_params *sdram_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, params, channel); + } + + return 0; +} + static int sdram_init(struct dram_info *dram, struct rk3399_sdram_params *sdram_params) { unsigned char dramtype = sdram_params->base.dramtype; unsigned int ddr_freq = sdram_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"); @@ -1275,37 +1314,60 @@ 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++) { + sdram_params->ch[ch].cap_info.rank = 2; + for (rank = 2; rank != 0; rank--) { + ret = pctl_init(dram, sdram_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 >= sdram_params->base.num_channels) - continue; + sdram_params->ch[ch].cap_info.rank = rank; - ret = pctl_cfg(dram, chan, channel, sdram_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 (sdram_params->base.dramtype == LPDDR3) + training_flag |= PI_CA_TRAINING; - /* start to trigger initialization */ - pctl_start(dram, sdram_params, channel); + if (!(data_training(&dram->chan[ch], ch, + sdram_params, training_flag))) + break; + } + /* Computed rank with associated channel number */ + sdram_params->ch[ch].cap_info.rank = rank; + } - /* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */ - if (dramtype == LPDDR3) - udelay(10); + sdram_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 = + &sdram_params->ch[channel].cap_info; - if (data_training(chan, channel, - sdram_params, PI_FULL_TRAINING)) { - printf("%s: data training failed\n", __func__); - return -EIO; + if (cap_info->rank == 0) { + clear_channel_params(sdram_params, channel); + continue; + } else { + sdram_params->base.num_channels++; } - set_ddrconfig(chan, sdram_params, channel, - sdram_params->ch[channel].cap_info.ddrconfig); + debug("Channel "); + debug(channel ? "1: " : "0: "); + + set_ddrconfig(chan, sdram_params, channel, cap_info->ddrconfig); + } + + if (sdram_params->base.num_channels == 0) { + printf("%s: ", __func__); + printf(" - %dMHz failed!\n", sdram_params->base.ddr_freq); + return -EINVAL; } sdram_params->base.stride = calculate_stride(sdram_params); -- 2.18.0.321.gffc6fa0e3 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jagan Teki Date: Tue, 11 Jun 2019 20:20:53 +0530 Subject: [U-Boot] [PATCH 50/92] ram: rk3399: Add rank detection support In-Reply-To: <20190611145135.21399-1-jagan@amarulasolutions.com> References: <20190611145135.21399-1-jagan@amarulasolutions.com> Message-ID: <20190611145135.21399-51-jagan@amarulasolutions.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de 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 Signed-off-by: YouMin Chen --- drivers/ram/rockchip/sdram_rk3399.c | 112 +++++++++++++++++++++------- 1 file changed, 87 insertions(+), 25 deletions(-) diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 033b2730a6..b658d7d1ab 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -1257,13 +1257,52 @@ static unsigned char calculate_stride(struct rk3399_sdram_params *sdram_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, params, channel); + } + + return 0; +} + static int sdram_init(struct dram_info *dram, struct rk3399_sdram_params *sdram_params) { unsigned char dramtype = sdram_params->base.dramtype; unsigned int ddr_freq = sdram_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"); @@ -1275,37 +1314,60 @@ 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++) { + sdram_params->ch[ch].cap_info.rank = 2; + for (rank = 2; rank != 0; rank--) { + ret = pctl_init(dram, sdram_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 >= sdram_params->base.num_channels) - continue; + sdram_params->ch[ch].cap_info.rank = rank; - ret = pctl_cfg(dram, chan, channel, sdram_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 (sdram_params->base.dramtype == LPDDR3) + training_flag |= PI_CA_TRAINING; - /* start to trigger initialization */ - pctl_start(dram, sdram_params, channel); + if (!(data_training(&dram->chan[ch], ch, + sdram_params, training_flag))) + break; + } + /* Computed rank with associated channel number */ + sdram_params->ch[ch].cap_info.rank = rank; + } - /* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */ - if (dramtype == LPDDR3) - udelay(10); + sdram_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 = + &sdram_params->ch[channel].cap_info; - if (data_training(chan, channel, - sdram_params, PI_FULL_TRAINING)) { - printf("%s: data training failed\n", __func__); - return -EIO; + if (cap_info->rank == 0) { + clear_channel_params(sdram_params, channel); + continue; + } else { + sdram_params->base.num_channels++; } - set_ddrconfig(chan, sdram_params, channel, - sdram_params->ch[channel].cap_info.ddrconfig); + debug("Channel "); + debug(channel ? "1: " : "0: "); + + set_ddrconfig(chan, sdram_params, channel, cap_info->ddrconfig); + } + + if (sdram_params->base.num_channels == 0) { + printf("%s: ", __func__); + printf(" - %dMHz failed!\n", sdram_params->base.ddr_freq); + return -EINVAL; } sdram_params->base.stride = calculate_stride(sdram_params); -- 2.18.0.321.gffc6fa0e3