From mboxrd@z Thu Jan 1 00:00:00 1970 From: Kever Yang Date: Fri, 07 Oct 2016 17:14:14 +0800 Subject: [U-Boot] [PATCH v2 2/3] rk3288: sdram: auto-detect the capacity In-Reply-To: References: <1474342101-21766-1-git-send-email-kever.yang@rock-chips.com> <1474342101-21766-3-git-send-email-kever.yang@rock-chips.com> Message-ID: <57F76766.5020306@rock-chips.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Hi Simon, On 09/23/2016 10:53 AM, Simon Glass wrote: > Hi Kever, > > On 19 September 2016 at 21:28, Kever Yang 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 >> --- >> >> 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 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 > > >