[U-Boot] [PATCH v3 43/57] ram: rk3399: Add LPPDR4 mr detection

Kever Yang kever.yang at rock-chips.com
Tue Jul 16 13:18:27 UTC 2019


On 2019/7/16 下午7:57, Jagan Teki wrote:
> Like data training in other sdram types, mr detection need
> to taken care for lpddr4 with looped rank and associated
> channel to make sure the proper configuration held.
>
> Once the mr detection successful for active and configured
> rank with channel number, the same can later reused during
> actual LPDDR4 initialization.
>
> So, add code to support for it.
>
> 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 | 226 ++++++++++++++++++++++++++++
>   1 file changed, 226 insertions(+)
>
> diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c
> index da01f08732..623685e3c5 100644
> --- a/drivers/ram/rockchip/sdram_rk3399.c
> +++ b/drivers/ram/rockchip/sdram_rk3399.c
> @@ -1470,6 +1470,7 @@ static void dram_all_config(struct dram_info *dram,
>   	clrsetbits_le32(&dram->cru->glb_rst_con, 0x3, 0x3);
>   }
>   
> +#if !defined(CONFIG_RAM_RK3399_LPDDR4)
>   static int default_data_training(struct dram_info *dram, u32 channel, u8 rank,
>   				 struct rk3399_sdram_params *params)
>   {
> @@ -1486,6 +1487,7 @@ static int default_data_training(struct dram_info *dram, u32 channel, u8 rank,
>   
>   	return data_training(dram, channel, params, training_flag);
>   }
> +#endif
>   
>   static int switch_to_phy_index1(struct dram_info *dram,
>   				const struct rk3399_sdram_params *params)
> @@ -1532,6 +1534,226 @@ static int switch_to_phy_index1(struct dram_info *dram,
>   	return 0;
>   }
>   
> +#if defined(CONFIG_RAM_RK3399_LPDDR4)
> +static u32 get_ddr_stride(struct rk3399_pmusgrf_regs *pmusgrf)
> +{
> +	return ((readl(&pmusgrf->soc_con4) >> 10) & 0x1F);
> +}
> +
> +static void set_ddr_stride(struct rk3399_pmusgrf_regs *pmusgrf, u32 stride)
> +{
> +	rk_clrsetreg(&pmusgrf->soc_con4, 0x1f << 10, stride << 10);
> +}
> +
> +static void set_cap_relate_config(const struct chan_info *chan,
> +				  struct rk3399_sdram_params *params,
> +				  unsigned int channel)
> +{
> +	u32 *denali_ctl = chan->pctl->denali_ctl;
> +	u32 tmp;
> +	struct rk3399_msch_timings *noc_timing;
> +
> +	if (params->base.dramtype == LPDDR3) {
> +		tmp = (8 << params->ch[channel].cap_info.bw) /
> +			(8 << params->ch[channel].cap_info.dbw);
> +
> +		/**
> +		 * memdata_ratio
> +		 * 1 -> 0, 2 -> 1, 4 -> 2
> +		 */
> +		clrsetbits_le32(&denali_ctl[197], 0x7,
> +				(tmp >> 1));
> +		clrsetbits_le32(&denali_ctl[198], 0x7 << 8,
> +				(tmp >> 1) << 8);
> +	}
> +
> +	noc_timing = &params->ch[channel].noc_timings;
> +
> +	/*
> +	 * noc timing bw relate timing is 32 bit, and real bw is 16bit
> +	 * actually noc reg is setting at function dram_all_config
> +	 */
> +	if (params->ch[channel].cap_info.bw == 16 &&
> +	    noc_timing->ddrmode.b.mwrsize == 2) {
> +		if (noc_timing->ddrmode.b.burstsize)
> +			noc_timing->ddrmode.b.burstsize -= 1;
> +		noc_timing->ddrmode.b.mwrsize -= 1;
> +		noc_timing->ddrtimingc0.b.burstpenalty *= 2;
> +		noc_timing->ddrtimingc0.b.wrtomwr *= 2;
> +	}
> +}
> +
> +static u32 calculate_ddrconfig(struct rk3399_sdram_params *params, u32 channel)
> +{
> +	unsigned int cs0_row = params->ch[channel].cap_info.cs0_row;
> +	unsigned int col = params->ch[channel].cap_info.col;
> +	unsigned int bw = params->ch[channel].cap_info.bw;
> +	u16  ddr_cfg_2_rbc[] = {
> +		/*
> +		 * [6]	  highest bit col
> +		 * [5:3]  max row(14+n)
> +		 * [2]    insertion row
> +		 * [1:0]  col(9+n),col, data bus 32bit
> +		 *
> +		 * highbitcol, max_row, insertion_row,  col
> +		 */
> +		((0 << 6) | (2 << 3) | (0 << 2) | 0), /* 0 */
> +		((0 << 6) | (2 << 3) | (0 << 2) | 1), /* 1 */
> +		((0 << 6) | (1 << 3) | (0 << 2) | 2), /* 2 */
> +		((0 << 6) | (0 << 3) | (0 << 2) | 3), /* 3 */
> +		((0 << 6) | (2 << 3) | (1 << 2) | 1), /* 4 */
> +		((0 << 6) | (1 << 3) | (1 << 2) | 2), /* 5 */
> +		((1 << 6) | (0 << 3) | (0 << 2) | 2), /* 6 */
> +		((1 << 6) | (1 << 3) | (0 << 2) | 2), /* 7 */
> +	};
> +	u32 i;
> +
> +	col -= (bw == 2) ? 0 : 1;
> +	col -= 9;
> +
> +	for (i = 0; i < 4; i++) {
> +		if ((col == (ddr_cfg_2_rbc[i] & 0x3)) &&
> +		    (cs0_row <= (((ddr_cfg_2_rbc[i] >> 3) & 0x7) + 14)))
> +			break;
> +	}
> +
> +	if (i >= 4)
> +		i = -EINVAL;
> +
> +	return i;
> +}
> +
> +/**
> + * read mr_num mode register
> + * rank = 1: cs0
> + * rank = 2: cs1
> + */
> +static int read_mr(struct rk3399_ddr_pctl_regs *ddr_pctl_regs, u32 rank,
> +		   u32 mr_num, u32 *buf)
> +{
> +	s32 timeout = 100;
> +
> +	writel(((1 << 16) | (((rank == 2) ? 1 : 0) << 8) | mr_num) << 8,
> +	       &ddr_pctl_regs->denali_ctl[118]);
> +
> +	while (0 == (readl(&ddr_pctl_regs->denali_ctl[203]) &
> +			((1 << 21) | (1 << 12)))) {
> +		udelay(1);
> +
> +		if (timeout <= 0) {
> +			printf("%s: pctl timeout!\n", __func__);
> +			return -ETIMEDOUT;
> +		}
> +
> +		timeout--;
> +	}
> +
> +	if (!(readl(&ddr_pctl_regs->denali_ctl[203]) & (1 << 12))) {
> +		*buf = readl(&ddr_pctl_regs->denali_ctl[119]) & 0xFF;
> +	} else {
> +		printf("%s: read mr failed with 0x%x status\n", __func__,
> +		       readl(&ddr_pctl_regs->denali_ctl[17]) & 0x3);
> +		*buf = 0;
> +	}
> +
> +	setbits_le32(&ddr_pctl_regs->denali_ctl[205], (1 << 21) | (1 << 12));
> +
> +	return 0;
> +}
> +
> +static int lpddr4_mr_detect(struct dram_info *dram, u32 channel, u8 rank,
> +			    struct rk3399_sdram_params *params)
> +{
> +	u64 cs0_cap;
> +	u32 stride;
> +	u32 cs = 0, col = 0, bk = 0, bw = 0, row_3_4 = 0;
> +	u32 cs0_row = 0, cs1_row = 0, ddrconfig = 0;
> +	u32 mr5, mr12, mr14;
> +	struct chan_info *chan = &dram->chan[channel];
> +	struct rk3399_ddr_pctl_regs *ddr_pctl_regs = chan->pctl;
> +	void __iomem *addr = NULL;
> +	int ret = 0;
> +	u32 val;
> +
> +	stride = get_ddr_stride(dram->pmusgrf);
> +
> +	if (params->ch[channel].cap_info.col == 0) {
> +		ret = -EPERM;
> +		goto end;
> +	}
> +
> +	cs = params->ch[channel].cap_info.rank;
> +	col = params->ch[channel].cap_info.col;
> +	bk = params->ch[channel].cap_info.bk;
> +	bw = params->ch[channel].cap_info.bw;
> +	row_3_4 = params->ch[channel].cap_info.row_3_4;
> +	cs0_row = params->ch[channel].cap_info.cs0_row;
> +	cs1_row = params->ch[channel].cap_info.cs1_row;
> +	ddrconfig = params->ch[channel].cap_info.ddrconfig;
> +
> +	/* 2GB */
> +	params->ch[channel].cap_info.rank = 2;
> +	params->ch[channel].cap_info.col = 10;
> +	params->ch[channel].cap_info.bk = 3;
> +	params->ch[channel].cap_info.bw = 2;
> +	params->ch[channel].cap_info.row_3_4 = 0;
> +	params->ch[channel].cap_info.cs0_row = 15;
> +	params->ch[channel].cap_info.cs1_row = 15;
> +	params->ch[channel].cap_info.ddrconfig = 1;
> +
> +	set_memory_map(chan, channel, params);
> +	params->ch[channel].cap_info.ddrconfig =
> +			calculate_ddrconfig(params, channel);
> +	set_ddrconfig(chan, params, channel,
> +		      params->ch[channel].cap_info.ddrconfig);
> +	set_cap_relate_config(chan, params, channel);
> +
> +	cs0_cap = (1 << (params->ch[channel].cap_info.bw
> +			+ params->ch[channel].cap_info.col
> +			+ params->ch[channel].cap_info.bk
> +			+ params->ch[channel].cap_info.cs0_row));
> +
> +	if (params->ch[channel].cap_info.row_3_4)
> +		cs0_cap = cs0_cap * 3 / 4;
> +
> +	if (channel == 0)
> +		set_ddr_stride(dram->pmusgrf, 0x17);
> +	else
> +		set_ddr_stride(dram->pmusgrf, 0x18);
> +
> +	/* read and write data to DRAM, avoid be optimized by compiler. */
> +	if (rank == 1)
> +		addr = (void __iomem *)0x100;
> +	else if (rank == 2)
> +		addr = (void __iomem *)(cs0_cap + 0x100);
> +
> +	val = readl(addr);
> +	writel(val + 1, addr);
> +
> +	read_mr(ddr_pctl_regs, rank, 5, &mr5);
> +	read_mr(ddr_pctl_regs, rank, 12, &mr12);
> +	read_mr(ddr_pctl_regs, rank, 14, &mr14);
> +
> +	if (mr5 == 0 || mr12 != 0x4d || mr14 != 0x4d) {
> +		ret = -EINVAL;
> +		goto end;
> +	}
> +end:
> +	params->ch[channel].cap_info.rank = cs;
> +	params->ch[channel].cap_info.col = col;
> +	params->ch[channel].cap_info.bk = bk;
> +	params->ch[channel].cap_info.bw = bw;
> +	params->ch[channel].cap_info.row_3_4 = row_3_4;
> +	params->ch[channel].cap_info.cs0_row = cs0_row;
> +	params->ch[channel].cap_info.cs1_row = cs1_row;
> +	params->ch[channel].cap_info.ddrconfig = ddrconfig;
> +
> +	set_ddr_stride(dram->pmusgrf, stride);
> +
> +	return ret;
> +}
> +#endif /* CONFIG_RAM_RK3399_LPDDR4 */
> +
>   static unsigned char calculate_stride(struct rk3399_sdram_params *params)
>   {
>   	unsigned int stride = params->base.stride;
> @@ -1762,7 +1984,11 @@ static int conv_of_platdata(struct udevice *dev)
>   #endif
>   
>   static const struct sdram_rk3399_ops rk3399_ops = {
> +#if !defined(CONFIG_RAM_RK3399_LPDDR4)
>   	.data_training = default_data_training,
> +#else
> +	.data_training = lpddr4_mr_detect,
> +#endif
>   };
>   
>   static int rk3399_dmc_init(struct udevice *dev)




More information about the U-Boot mailing list