From: Kever Yang <kever.yang@rock-chips.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v2 2/3] rk3288: sdram: auto-detect the capacity
Date: Fri, 07 Oct 2016 17:14:14 +0800 [thread overview]
Message-ID: <57F76766.5020306@rock-chips.com> (raw)
In-Reply-To: <CAPnjgZ1vUo8OSTzfF_V+_uoiDbx2uKAxOq_m0f1pgD8WrwiL=Q@mail.gmail.com>
Hi Simon,
On 09/23/2016 10:53 AM, Simon Glass wrote:
> Hi Kever,
>
> On 19 September 2016 at 21:28, Kever Yang <kever.yang@rock-chips.com> wrote:
>> Add support for rk3288 dram capacity auto detect, support DDR3 and
>> LPDDR3, DDR2 is not supported.
>> The program will automatically detect:
>> - channel number
>> - rank number
>> - column address number
>> - row address number
>>
>> The dts file do not need to describe those info after apply this patch.
>>
>> Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
>> ---
>>
>> Changes in v2:
>> - update code for OF_PLATDATA enabled
>> - bug fix for ddrconfig
>>
>> arch/arm/mach-rockchip/rk3288/sdram_rk3288.c | 244 ++++++++++++++++++++++-----
>> 1 file changed, 202 insertions(+), 42 deletions(-)
> Tested on firefly-rk3288:
> Tested-by: Simon Glass <sjg@chromium.org>
Thanks for your test.
>> diff --git a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
>> index cf9ef2e..b3dc251 100644
>> --- a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
>> +++ b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c
>> @@ -57,6 +57,10 @@ struct rk3288_sdram_params {
>> struct regmap *map;
>> };
>>
>> +#define TEST_PATTEN 0x5aa5f00f
>> +#define DQS_GATE_TRAINING_ERROR_RANK0 (1 << 4)
>> +#define DQS_GATE_TRAINING_ERROR_RANK1 (2 << 4)
>> +
>> #ifdef CONFIG_SPL_BUILD
>> static void copy_to_reg(u32 *dest, const u32 *src, u32 n)
>> {
>> @@ -214,7 +218,7 @@ static void ddr_set_en_bst_odt(struct rk3288_grf *grf, uint channel,
>> }
>>
>> static void pctl_cfg(u32 channel, struct rk3288_ddr_pctl *pctl,
>> - const struct rk3288_sdram_params *sdram_params,
>> + struct rk3288_sdram_params *sdram_params,
>> struct rk3288_grf *grf)
>> {
>> unsigned int burstlen;
>> @@ -264,7 +268,7 @@ static void pctl_cfg(u32 channel, struct rk3288_ddr_pctl *pctl,
>> }
>>
>> static void phy_cfg(const struct chan_info *chan, u32 channel,
>> - const struct rk3288_sdram_params *sdram_params)
>> + struct rk3288_sdram_params *sdram_params)
>> {
>> struct rk3288_ddr_publ *publ = chan->publ;
>> struct rk3288_msch *msch = chan->msch;
>> @@ -446,7 +450,7 @@ static void set_bandwidth_ratio(const struct chan_info *chan, u32 channel,
>> }
>>
>> static int data_training(const struct chan_info *chan, u32 channel,
>> - const struct rk3288_sdram_params *sdram_params)
>> + struct rk3288_sdram_params *sdram_params)
>> {
>> unsigned int j;
>> int ret = 0;
>> @@ -549,7 +553,7 @@ static void move_to_access_state(const struct chan_info *chan)
>> }
>>
>> static void dram_cfg_rbc(const struct chan_info *chan, u32 chnum,
>> - const struct rk3288_sdram_params *sdram_params)
>> + struct rk3288_sdram_params *sdram_params)
>> {
>> struct rk3288_ddr_publ *publ = chan->publ;
>>
>> @@ -563,7 +567,7 @@ static void dram_cfg_rbc(const struct chan_info *chan, u32 chnum,
>> }
>>
>> static void dram_all_config(const struct dram_info *dram,
>> - const struct rk3288_sdram_params *sdram_params)
>> + struct rk3288_sdram_params *sdram_params)
>> {
>> unsigned int chan;
>> u32 sys_reg = 0;
>> @@ -589,9 +593,173 @@ static void dram_all_config(const struct dram_info *dram,
>> writel(sys_reg, &dram->pmu->sys_reg[2]);
>> rk_clrsetreg(&dram->sgrf->soc_con2, 0x1f, sdram_params->base.stride);
>> }
>> +const int ddrconf_table[] = {
>> + /* row col,bw */
>> + 0,
>> + ((1 << 4) | 1),
>> + ((2 << 4) | 1),
>> + ((3 << 4) | 1),
>> + ((4 << 4) | 1),
>> + ((1 << 4) | 2),
>> + ((2 << 4) | 2),
>> + ((3 << 4) | 2),
>> + ((1 << 4) | 0),
>> + ((2 << 4) | 0),
>> + ((3 << 4) | 0),
>> + 0,
>> + 0,
>> + 0,
>> + 0,
>> + ((4 << 4) | 2),
>> +};
>> +
>> +static int sdram_rank_bw_detect(struct dram_info *dram, int channel,
>> + struct rk3288_sdram_params *sdram_params)
>> +{
>> + int reg;
>> + int need_trainig = 0;
>> + const struct chan_info *chan = &dram->chan[channel];
>> + struct rk3288_ddr_publ *publ = chan->publ;
>> +
>> + if (-1 == data_training(chan, channel, sdram_params)) {
>> + reg = readl(&publ->datx8[0].dxgsr[0]);
>> + /* Check the result for rank 0 */
>> + if ((channel == 0) && (reg & DQS_GATE_TRAINING_ERROR_RANK0)) {
>> + debug("data training fail!\n");
>> + return -EIO;
>> + } else if ((channel == 1) &&
>> + (reg & DQS_GATE_TRAINING_ERROR_RANK0)) {
>> + sdram_params->num_channels = 1;
>> + }
>> +
>> + /* Check the result for rank 1 */
>> + if (reg & DQS_GATE_TRAINING_ERROR_RANK1) {
>> + sdram_params->ch[channel].rank = 1;
>> + clrsetbits_le32(&publ->pgcr, 0xF << 18,
>> + sdram_params->ch[channel].rank << 18);
>> + need_trainig = 1;
>> + }
>> + reg = readl(&publ->datx8[2].dxgsr[0]);
>> + if (reg & (1 << 4)) {
>> + sdram_params->ch[channel].bw = 1;
>> + set_bandwidth_ratio(chan, channel,
>> + sdram_params->ch[channel].bw,
>> + dram->grf);
>> + need_trainig = 1;
>> + }
>> + }
>> + /* Assume the Die bit width are the same with the chip bit width*/
>> + sdram_params->ch[channel].dbw = sdram_params->ch[channel].bw;
>> +
>> + if (need_trainig &&
>> + (-1 == data_training(chan, channel, sdram_params))) {
>> + if (sdram_params->base.dramtype == LPDDR3) {
>> + ddr_phy_ctl_reset(dram->cru, channel, 1);
>> + udelay(10);
>> + ddr_phy_ctl_reset(dram->cru, channel, 0);
>> + udelay(10);
>> + }
>> + debug("2nd data training failed!");
>> + return -EIO;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void sdram_col_row_detect(struct dram_info *dram, int channel,
>> + struct rk3288_sdram_params *sdram_params)
>> +{
>> + int row, col;
>> + unsigned int addr;
>> + const struct chan_info *chan = &dram->chan[channel];
>> + struct rk3288_ddr_pctl *pctl = chan->pctl;
>> + struct rk3288_ddr_publ *publ = chan->publ;
>> + /* Detect col */
>> + for (col = 11; col >= 9; col--) {
>> + writel(0, CONFIG_SYS_SDRAM_BASE);
>> + addr = CONFIG_SYS_SDRAM_BASE +
>> + (1 << (col + sdram_params->ch[channel].bw - 1));
>> + writel(TEST_PATTEN, addr);
>> + if ((readl(addr) == TEST_PATTEN) &&
>> + (readl(CONFIG_SYS_SDRAM_BASE) == 0))
>> + break;
>> + }
>> + if (col == 8)
>> + debug("Col detect error\n");
> Tis is an error, so please return an error code and halt the board.
Will add return value and hang() if error happen.
>
>> + else
>> + sdram_params->ch[channel].col = col;
>> +
>> + move_to_config_state(publ, pctl);
>> + writel(4, &chan->msch->ddrconf);
>> + move_to_access_state(chan);
>> + /* Detect row*/
>> + for (row = 16; row >= 12; row--) {
>> + writel(0, CONFIG_SYS_SDRAM_BASE);
>> + addr = CONFIG_SYS_SDRAM_BASE + (1 << (row + 15 - 1));
>> + writel(TEST_PATTEN, addr);
>> + if ((readl(addr) == TEST_PATTEN) &&
>> + (readl(CONFIG_SYS_SDRAM_BASE) == 0))
>> + break;
>> + }
>> + if (row == 11)
>> + debug("Row detect error\n");
> Here also.
>
>> + else
>> + sdram_params->ch[channel].cs0_row = row;
>> + sdram_params->ch[channel].cs1_row = row;
>> + sdram_params->ch[channel].row_3_4 = 0;
>> + debug("chn %d col %d, row %d\n", channel, col, row);
>> +}
>> +
>> +static void sdram_get_niu_config(struct rk3288_sdram_params *sdram_params)
>> +{
>> + int i, tmp, size;
>> +
>> + tmp = sdram_params->ch[0].col - 9;
>> + tmp -= (sdram_params->ch[0].bw == 2) ? 0 : 1;
>> + tmp |= ((sdram_params->ch[0].cs0_row - 12) << 4);
>> + size = sizeof(ddrconf_table)/sizeof(ddrconf_table[0]);
>> + for (i = 0; i < size; i++)
>> + if (tmp == ddrconf_table[i])
>> + break;
>> + if (i >= size)
>> + debug("niu config not found\n");
> And here
>
>> + else
>> + sdram_params->base.ddrconfig = i;
>> +}
>> +
>> +static void sdram_get_stride(struct rk3288_sdram_params *sdram_params)
>> +{
>> + int stride = -1;
>> + long cap = sdram_params->num_channels * (1u <<
>> + (sdram_params->ch[0].cs0_row +
>> + sdram_params->ch[0].col +
>> + (sdram_params->ch[0].rank - 1) +
>> + sdram_params->ch[0].bw +
>> + 3 - 20));
>> +
>> + switch (cap) {
>> + case 512:
>> + stride = 0;
>> + break;
>> + case 1024:
>> + stride = 5;
>> + break;
>> + case 2048:
>> + stride = 9;
>> + break;
>> + case 4096:
>> + stride = 0xd;
>> + break;
>> + default:
>> + stride = -1;
>> + debug("could not find correct stride, cap error!\n");
> And here
>
>> + break;
>> + }
>> + sdram_params->base.stride = stride;
>> +}
>>
>> static int sdram_init(struct dram_info *dram,
>> - const struct rk3288_sdram_params *sdram_params)
>> + struct rk3288_sdram_params *sdram_params)
>> {
>> int channel;
>> int zqcr;
>> @@ -619,12 +787,13 @@ static int sdram_init(struct dram_info *dram,
>> struct rk3288_ddr_pctl *pctl = chan->pctl;
>> struct rk3288_ddr_publ *publ = chan->publ;
>>
>> + if (channel)
>> + rk_clrsetreg(&dram->sgrf->soc_con2, 0x1f, 0x17);
>> + else
>> + rk_clrsetreg(&dram->sgrf->soc_con2, 0x1f, 0x1a);
> What are these magic numbers? Please can you add defines?
This is DDR stride setting, I will add comments in stride structure.
>
>> phy_pctrl_reset(dram->cru, publ, channel);
>> phy_dll_bypass_set(publ, sdram_params->base.ddr_freq);
>>
>> - if (channel >= sdram_params->num_channels)
>> - continue;
>> -
>> dfi_cfg(pctl, sdram_params->base.dramtype);
>>
>> pctl_cfg(channel, pctl, sdram_params, dram->grf);
>> @@ -658,16 +827,20 @@ static int sdram_init(struct dram_info *dram,
>> udelay(1);
>> }
>>
>> + /* Using 32bit bus width for detect */
>> + sdram_params->ch[channel].bw = 2;
>> set_bandwidth_ratio(chan, channel,
>> sdram_params->ch[channel].bw, dram->grf);
>> /*
>> - * set cs
>> + * set cs, using n=3 for detect
>> * CS0, n=1
>> * CS1, n=2
>> * CS0 & CS1, n = 3
>> */
>> + sdram_params->ch[channel].rank = 2,
>> clrsetbits_le32(&publ->pgcr, 0xF << 18,
>> (sdram_params->ch[channel].rank | 1) << 18);
>> +
>> /* DS=40ohm,ODT=155ohm */
>> zqcr = 1 << ZDEN_SHIFT | 2 << PU_ONDIE_SHIFT |
>> 2 << PD_ONDIE_SHIFT | 0x19 << PU_OUTPUT_SHIFT |
>> @@ -693,16 +866,8 @@ static int sdram_init(struct dram_info *dram,
>> }
>> }
>>
>> - if (-1 == data_training(chan, channel, sdram_params)) {
>> - if (sdram_params->base.dramtype == LPDDR3) {
>> - ddr_phy_ctl_reset(dram->cru, channel, 1);
>> - udelay(10);
>> - ddr_phy_ctl_reset(dram->cru, channel, 0);
>> - udelay(10);
>> - }
>> - debug("failed!");
>> - return -EIO;
>> - }
>> + /* Detect the rank and bit-width with data-training */
>> + sdram_rank_bw_detect(dram, channel, sdram_params);
>>
>> if (sdram_params->base.dramtype == LPDDR3) {
>> u32 i;
>> @@ -710,8 +875,18 @@ static int sdram_init(struct dram_info *dram,
>> for (i = 0; i < 17; i++)
>> send_command_op(pctl, 1, MRR_CMD, i, 0);
>> }
>> + writel(15, &chan->msch->ddrconf);
>> move_to_access_state(chan);
>> + /* DDR3 and LPDDR3 are always 8 bank, no need detect */
>> + sdram_params->ch[channel].bk = 3;
> Do you have a define for 3?
This is address bits need to use, eg. 3 bits for 8 bank here. will add
comments in structure.
Thanks,
- Kever
>
>> + /* Detect Col and Row number*/
>> + sdram_col_row_detect(dram, channel, sdram_params);
>> }
>> + /* Find NIU DDR configuration */
>> + sdram_get_niu_config(sdram_params);
>> + /* Find stride setting */
>> + sdram_get_stride(sdram_params);
>> +
> Check errors here. At the very top level, printf a short error.
>
>> dram_all_config(dram, sdram_params);
>> debug("%s done\n", __func__);
>>
>> @@ -743,7 +918,6 @@ size_t sdram_size_mb(struct rk3288_pmu *pmu)
>> SYS_REG_BW_MASK));
>> row_3_4 = sys_reg >> SYS_REG_ROW_3_4_SHIFT(ch) &
>> SYS_REG_ROW_3_4_MASK;
>> -
>> chipsize_mb = (1 << (cs0_row + col + bk + bw - 20));
>>
>> if (rank > 1)
>> @@ -814,21 +988,10 @@ static int rk3288_dmc_ofdata_to_platdata(struct udevice *dev)
>> struct rk3288_sdram_params *params = dev_get_platdata(dev);
>> const void *blob = gd->fdt_blob;
>> int node = dev->of_offset;
>> - int i, ret;
>> -
>> - params->num_channels = fdtdec_get_int(blob, node,
>> - "rockchip,num-channels", 1);
>> - for (i = 0; i < params->num_channels; i++) {
>> - ret = fdtdec_get_byte_array(blob, node,
>> - "rockchip,sdram-channel",
>> - (u8 *)¶ms->ch[i],
>> - sizeof(params->ch[i]));
>> - if (ret) {
>> - debug("%s: Cannot read rockchip,sdram-channel\n",
>> - __func__);
>> - return -EINVAL;
>> - }
>> - }
>> + int ret;
>> +
>> + /* Rk3288 supports dual-channel, set default channel num to 2 */
>> + params->num_channels = 2;
>> ret = fdtdec_get_int_array(blob, node, "rockchip,pctl-timing",
>> (u32 *)¶ms->pctl_timing,
>> sizeof(params->pctl_timing) / sizeof(u32));
>> @@ -869,18 +1032,15 @@ static int conv_of_platdata(struct udevice *dev)
>> {
>> struct rk3288_sdram_params *plat = dev_get_platdata(dev);
>> struct dtd_rockchip_rk3288_dmc *of_plat = &plat->of_plat;
>> - int i, ret;
>> + int ret;
>>
>> - for (i = 0; i < 2; i++) {
>> - memcpy(&plat->ch[i], of_plat->rockchip_sdram_channel,
>> - sizeof(plat->ch[i]));
>> - }
>> memcpy(&plat->pctl_timing, of_plat->rockchip_pctl_timing,
>> sizeof(plat->pctl_timing));
>> memcpy(&plat->phy_timing, of_plat->rockchip_phy_timing,
>> sizeof(plat->phy_timing));
>> memcpy(&plat->base, of_plat->rockchip_sdram_params, sizeof(plat->base));
>> - plat->num_channels = of_plat->rockchip_num_channels;
>> + /* Rk3288 supports dual-channel, set default channel num to 2 */
>> + plat->num_channels = 2;
>> ret = regmap_init_mem_platdata(dev, of_plat->reg,
>> ARRAY_SIZE(of_plat->reg) / 2,
>> &plat->map);
>> --
>> 1.9.1
>>
> Regards,
> Simon
>
>
>
next prev parent reply other threads:[~2016-10-07 9:14 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-09-20 3:28 [U-Boot] [PATCH v2 0/3] Add sdram capacity auto detect for rk3288 Kever Yang
2016-09-20 3:28 ` [U-Boot] [PATCH v2 1/3] rk3288: config change for enable dram capacity auto-detect Kever Yang
2016-09-20 13:21 ` Sandy Patterson
2016-09-21 3:00 ` Kever Yang
2016-09-21 11:53 ` Sandy Patterson
2016-09-22 2:10 ` Kever Yang
2016-09-20 3:28 ` [U-Boot] [PATCH v2 2/3] rk3288: sdram: auto-detect the capacity Kever Yang
2016-09-23 2:53 ` Simon Glass
2016-10-07 9:14 ` Kever Yang [this message]
2016-10-06 0:28 ` Vagrant Cascadian
2016-09-20 3:28 ` [U-Boot] [PATCH v2 3/3] dts: rk3288: remove node in dmc which not need anymore Kever Yang
2016-09-23 2:58 ` Simon Glass
2016-10-06 0:28 ` Vagrant Cascadian
2016-09-20 15:04 ` [U-Boot] [PATCH v2 0/3] Add sdram capacity auto detect for rk3288 Sandy Patterson
2016-09-21 2:56 ` Kever Yang
2016-09-21 12:41 ` Sandy Patterson
2016-09-22 2:15 ` Kever Yang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=57F76766.5020306@rock-chips.com \
--to=kever.yang@rock-chips.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.