[U-Boot] [RESEND PATCH v3 1/7] armv8: lsch3: Add serdes and DDR voltage setup

Rajesh Bhagat rajesh.bhagat at nxp.com
Mon Sep 18 06:57:43 UTC 2017



> -----Original Message-----
> From: York Sun
> Sent: Friday, September 15, 2017 2:33 AM
> To: Rajesh Bhagat <rajesh.bhagat at nxp.com>; u-boot at lists.denx.de
> Cc: Prabhakar Kushwaha <prabhakar.kushwaha at nxp.com>; Ashish Kumar
> <ashish.kumar at nxp.com>
> Subject: Re: [RESEND PATCH v3 1/7] armv8: lsch3: Add serdes and DDR voltage
> setup
> 
> You have a lot of magic numbers and delays. See inline comments.
> 
> On 09/03/2017 11:24 PM, Rajesh Bhagat wrote:
> > Adds SERDES voltage and reset SERDES lanes API and makes
> > enable/disable DDR controller support 0.9V API common.
> >
> > Signed-off-by: Ashish Kumar <Ashish.Kumar at nxp.com>
> > Signed-off-by: Rajesh Bhagat <rajesh.bhagat at nxp.com>
> > ---
> > Changes in v3:
> >   Restructured LS1088A VID support to use common VID driver
> >   Cosmetic review comments fixed
> >   Added __iomem for accessing registers
> >
> > Changes in v2:
> >   Checkpatch errors fixed
> >
> >   .../cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c    | 274
> +++++++++++++++++++++
> >   arch/arm/cpu/armv8/fsl-layerscape/soc.c            |  34 +--
> >   .../include/asm/arch-fsl-layerscape/fsl_serdes.h   |   2 +-
> >   .../include/asm/arch-fsl-layerscape/immap_lsch3.h  |  34 +++
> >   arch/arm/include/asm/arch-fsl-layerscape/soc.h     |   1 +
> >   5 files changed, 327 insertions(+), 18 deletions(-)
> >
> > diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c
> > b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c
> > index 179cac6..39f2cdf 100644
> > --- a/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c
> > +++ b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c
> > @@ -158,6 +158,280 @@ void serdes_init(u32 sd, u32 sd_addr, u32 rcwsr, u32
> sd_prctl_mask,
> >   	serdes_prtcl_map[NONE] = 1;
> >   }
> >
> > +__weak int get_serdes_volt(void)
> > +{
> > +	return -1;
> > +}
> > +
> > +__weak int set_serdes_volt(int svdd)
> > +{
> > +	return -1;
> > +}
> > +
> > +int setup_serdes_volt(u32 svdd)
> > +{
> > +	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
> > +	struct ccsr_serdes __iomem *serdes1_base;
> > +	u32 cfg_rcwsrds1 = gur_in32(&gur->rcwsr[FSL_CHASSIS3_SRDS1_REGSR -
> > +1]); #ifdef CONFIG_SYS_FSL_SRDS_2
> > +	struct ccsr_serdes __iomem *serdes2_base;
> > +	u32 cfg_rcwsrds2 = gur_in32(&gur->rcwsr[FSL_CHASSIS3_SRDS2_REGSR -
> > +1]); #endif
> > +	u32 cfg_tmp, reg = 0;
> > +	int svdd_cur, svdd_tar;
> > +	int ret = 1;
> > +	int i;
> > +
> > +	/* Only support switch SVDD to 900mV */
> > +	if (svdd != 900)
> > +		return -1;
> > +
> > +	/* Scale up to the LTC resolution is 1/4096V */
> > +	svdd = (svdd * 4096) / 1000;
> > +
> > +	svdd_tar = svdd;
> > +	svdd_cur = get_serdes_volt();
> > +	if (svdd_cur < 0)
> > +		return -EINVAL;
> > +
> > +	debug("%s: current SVDD: %x; target SVDD: %x\n",
> > +	      __func__, svdd_cur, svdd_tar);
> > +	if (svdd_cur == svdd_tar)
> > +		return 0;
> > +
> > +	serdes1_base = (void *)CONFIG_SYS_FSL_LSCH3_SERDES_ADDR;
> > +#ifdef CONFIG_SYS_FSL_SRDS_2
> > +	serdes2_base =  (void *)(CONFIG_SYS_FSL_LSCH3_SERDES_ADDR +
> > +0x10000); #endif
> > +
> > +	/* Put the all enabled lanes in reset */ #ifdef
> > +CONFIG_SYS_FSL_SRDS_1
> > +	cfg_tmp = cfg_rcwsrds1 & FSL_CHASSIS3_SRDS1_PRTCL_MASK;
> > +	cfg_tmp >>= FSL_CHASSIS3_SRDS1_PRTCL_SHIFT;
> > +
> > +	for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
> > +		reg = in_le32(&serdes1_base->lane[i].gcr0);
> > +		reg &= 0xFF9FFFFF;
> > +		out_le32(&serdes1_base->lane[i].gcr0, reg);
> > +	}
> > +#endif
> 
> Please use local macros instead of magic numbers here and below.
> 

Will take care in v3 

> > +
> > +#ifdef CONFIG_SYS_FSL_SRDS_2
> > +	cfg_tmp = cfg_rcwsrds2 & FSL_CHASSIS3_SRDS2_PRTCL_MASK;
> > +	cfg_tmp >>= FSL_CHASSIS3_SRDS2_PRTCL_SHIFT;
> > +
> > +	for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
> > +		reg = in_le32(&serdes2_base->lane[i].gcr0);
> > +		reg &= 0xFF9FFFFF;
> > +		out_le32(&serdes2_base->lane[i].gcr0, reg);
> > +	}
> > +#endif
> > +
> > +	/* Put the all enabled PLL in reset */ #ifdef CONFIG_SYS_FSL_SRDS_1
> > +	cfg_tmp = cfg_rcwsrds1 & 0x3;
> > +	for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
> > +		reg = in_le32(&serdes1_base->bank[i].rstctl);
> > +		reg &= 0xFFFFFFBF;
> > +		reg |= 0x10000000;
> > +		out_le32(&serdes1_base->bank[i].rstctl, reg);
> > +	}
> > +	udelay(1);
> > +
> > +	reg = in_le32(&serdes1_base->bank[i].rstctl);
> > +	reg &= 0xFFFFFF1F;
> > +	out_le32(&serdes1_base->bank[i].rstctl, reg); #endif
> > +
> > +#ifdef CONFIG_SYS_FSL_SRDS_2
> > +	cfg_tmp = cfg_rcwsrds1 & 0xC;
> > +	cfg_tmp >>= 2;
> > +	for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
> > +		reg = in_le32(&serdes2_base->bank[i].rstctl);
> > +		reg &= 0xFFFFFFBF;
> > +		reg |= 0x10000000;
> > +		out_le32(&serdes2_base->bank[i].rstctl, reg);
> > +	}
> > +	udelay(1);
> 
> What's this delay for?
> 

These delays are part of SERDES reset requirements, each step of 
SERDES reset requires some delay to be added.

> > +
> > +	reg = in_le32(&serdes2_base->bank[i].rstctl);
> > +	reg &= 0xFFFFFF1F;
> > +	out_le32(&serdes2_base->bank[i].rstctl, reg); #endif
> > +
> > +	/* Put the Rx/Tx calibration into reset */ #ifdef
> > +CONFIG_SYS_FSL_SRDS_1
> > +	reg = in_le32(&serdes1_base->srdstcalcr);
> > +	reg &= 0xF7FFFFFF;
> > +	out_le32(&serdes1_base->srdstcalcr, reg);
> > +	reg = in_le32(&serdes1_base->srdsrcalcr);
> > +	reg &= 0xF7FFFFFF;
> > +	out_le32(&serdes1_base->srdsrcalcr, reg); #endif
> > +
> > +#ifdef CONFIG_SYS_FSL_SRDS_2
> > +	reg = in_le32(&serdes2_base->srdstcalcr);
> > +	reg &= 0xF7FFFFFF;
> > +	out_le32(&serdes2_base->srdstcalcr, reg);
> > +	reg = in_le32(&serdes2_base->srdsrcalcr);
> > +	reg &= 0xF7FFFFFF;
> > +	out_le32(&serdes2_base->srdsrcalcr, reg); #endif
> > +
> > +	ret = set_serdes_volt(svdd);
> > +	if (ret < 0) {
> > +		printf("could not change SVDD\n");
> > +		ret = -1;
> > +	}
> > +
> > +	/* For each PLL that's not disabled via RCW enable the SERDES */
> > +#ifdef CONFIG_SYS_FSL_SRDS_1
> > +	cfg_tmp = cfg_rcwsrds1 & 0x3;
> > +	for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
> > +		reg = in_le32(&serdes1_base->bank[i].rstctl);
> > +		reg |= 0x00000020;
> > +		out_le32(&serdes1_base->bank[i].rstctl, reg);
> > +		udelay(1);
> 
> Why delay here?
> 
> > +
> > +		reg = in_le32(&serdes1_base->bank[i].rstctl);
> > +		reg |= 0x00000080;
> > +		out_le32(&serdes1_base->bank[i].rstctl, reg);
> > +		udelay(1);
> 
> Here.
> 
> > +		/* Take the Rx/Tx calibration out of reset */
> > +		if (!(cfg_tmp == 0x3 && i == 1)) {
> > +			udelay(1);
> > +			reg = in_le32(&serdes1_base->srdstcalcr);
> > +			reg |= 0x08000000;
> > +			out_le32(&serdes1_base->srdstcalcr, reg);
> > +			reg = in_le32(&serdes1_base->srdsrcalcr);
> > +			reg |= 0x08000000;
> > +			out_le32(&serdes1_base->srdsrcalcr, reg);
> > +		}
> > +		udelay(1);
> 
> Why delay here?
> 
> > +	}
> > +#endif
> > +#ifdef CONFIG_SYS_FSL_SRDS_2
> > +	cfg_tmp = cfg_rcwsrds1 & 0xC;
> > +	cfg_tmp >>= 2;
> > +	for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
> > +		reg = in_le32(&serdes2_base->bank[i].rstctl);
> > +		reg |= 0x00000020;
> > +		out_le32(&serdes2_base->bank[i].rstctl, reg);
> > +		udelay(1);
> > +
> > +		reg = in_le32(&serdes2_base->bank[i].rstctl);
> > +		reg |= 0x00000080;
> > +		out_le32(&serdes2_base->bank[i].rstctl, reg);
> > +		udelay(1);
> > +
> > +		/* Take the Rx/Tx calibration out of reset */
> > +		if (!(cfg_tmp == 0x3 && i == 1)) {
> > +			udelay(1);
> > +			reg = in_le32(&serdes2_base->srdstcalcr);
> > +			reg |= 0x08000000;
> > +			out_le32(&serdes2_base->srdstcalcr, reg);
> > +			reg = in_le32(&serdes2_base->srdsrcalcr);
> > +			reg |= 0x08000000;
> > +			out_le32(&serdes2_base->srdsrcalcr, reg);
> > +		}
> > +		udelay(1);
> > +	}
> > +#endif
> 
> You have many duplicated code. Use functions or macros.
> 

Will take care in v3

> > +
> > +	/* Wait for at atleast 625us, ensure the PLLs being reset are locked */
> > +	udelay(800);
> 
> You said 625us, but using 800.
> 

It says atleast 625us, and delay is added for 800us. Again the SERDES requirement
states this. 

> > +
> > +#ifdef CONFIG_SYS_FSL_SRDS_1
> > +	cfg_tmp = cfg_rcwsrds1 & 0x3;
> > +	for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
> > +		/* if the PLL is not locked, set RST_ERR */
> > +		reg = in_le32(&serdes1_base->bank[i].pllcr0);
> > +		if (!((reg >> 23) & 0x1)) {
> > +			reg = in_le32(&serdes1_base->bank[i].rstctl);
> > +			reg |= 0x20000000;
> > +			out_le32(&serdes1_base->bank[i].rstctl, reg);
> > +		} else {
> > +			udelay(1);
> > +			reg = in_le32(&serdes1_base->bank[i].rstctl);
> > +			reg &= 0xFFFFFFEF;
> > +			reg |= 0x00000040;
> > +			out_le32(&serdes1_base->bank[i].rstctl, reg);
> > +			udelay(1);
> > +		}
> > +	}
> > +#endif
> > +
> > +#ifdef CONFIG_SYS_FSL_SRDS_2
> > +	cfg_tmp = cfg_rcwsrds1 & 0xC;
> > +	cfg_tmp >>= 2;
> > +
> > +	for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
> > +		reg = in_le32(&serdes2_base->bank[i].pllcr0);
> > +		if (!((reg >> 23) & 0x1)) {
> > +			reg = in_le32(&serdes2_base->bank[i].rstctl);
> > +			reg |= 0x20000000;
> > +			out_le32(&serdes2_base->bank[i].rstctl, reg);
> > +		} else {
> > +			udelay(1);
> > +			reg = in_le32(&serdes2_base->bank[i].rstctl);
> > +			reg &= 0xFFFFFFEF;
> > +			reg |= 0x00000040;
> > +			out_le32(&serdes2_base->bank[i].rstctl, reg);
> > +			udelay(1);
> > +		}
> > +	}
> > +#endif
> > +	/* Take the all enabled lanes out of reset */ #ifdef
> > +CONFIG_SYS_FSL_SRDS_1
> > +	cfg_tmp = cfg_rcwsrds1 & FSL_CHASSIS3_SRDS1_PRTCL_MASK;
> > +	cfg_tmp >>= FSL_CHASSIS3_SRDS1_PRTCL_SHIFT;
> > +
> > +	for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
> > +		reg = in_le32(&serdes1_base->lane[i].gcr0);
> > +		reg |= 0x00600000;
> > +		out_le32(&serdes1_base->lane[i].gcr0, reg);
> > +	}
> > +#endif
> > +#ifdef CONFIG_SYS_FSL_SRDS_2
> > +	cfg_tmp = cfg_rcwsrds2 & FSL_CHASSIS3_SRDS2_PRTCL_MASK;
> > +	cfg_tmp >>= FSL_CHASSIS3_SRDS2_PRTCL_SHIFT;
> > +
> > +	for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
> > +		reg = in_le32(&serdes2_base->lane[i].gcr0);
> > +		reg |= 0x00600000;
> > +		out_le32(&serdes2_base->lane[i].gcr0, reg);
> > +	}
> > +#endif
> > +
> > +	/* For each PLL being reset, and achieved PLL lock set RST_DONE */
> > +#ifdef CONFIG_SYS_FSL_SRDS_1
> > +	cfg_tmp = cfg_rcwsrds1 & 0x3;
> > +	for (i = 0; i < 2; i++) {
> > +		reg = in_le32(&serdes1_base->bank[i].pllcr0);
> > +		if (!(cfg_tmp & (0x1 << (1 - i))) && ((reg >> 23) & 0x1)) {
> > +			reg = in_le32(&serdes1_base->bank[i].rstctl);
> > +			reg |= 0x40000000;
> > +			out_le32(&serdes1_base->bank[i].rstctl, reg);
> > +		}
> > +	}
> > +#endif
> > +#ifdef CONFIG_SYS_FSL_SRDS_2
> > +	cfg_tmp = cfg_rcwsrds1 & 0xC;
> > +	cfg_tmp >>= 2;
> > +
> > +	for (i = 0; i < 2; i++) {
> > +		reg = in_le32(&serdes2_base->bank[i].pllcr0);
> > +		if (!(cfg_tmp & (0x1 << (1 - i))) && ((reg >> 23) & 0x1)) {
> > +			reg = in_le32(&serdes2_base->bank[i].rstctl);
> > +			reg |= 0x40000000;
> > +			out_le32(&serdes2_base->bank[i].rstctl, reg);
> > +		}
> > +	}
> > +#endif
> > +
> > +	return ret;
> > +}
> > +
> >   void fsl_serdes_init(void)
> >   {
> >   #if defined(CONFIG_FSL_MC_ENET) && !defined(CONFIG_SPL_BUILD) diff
> > --git a/arch/arm/cpu/armv8/fsl-layerscape/soc.c
> > b/arch/arm/cpu/armv8/fsl-layerscape/soc.c
> > index 83e2871..4e96c7b 100644
> > --- a/arch/arm/cpu/armv8/fsl-layerscape/soc.c
> > +++ b/arch/arm/cpu/armv8/fsl-layerscape/soc.c
> > @@ -404,23 +404,6 @@ static int setup_core_volt(u32 vdd)
> >   	return board_setup_core_volt(vdd);
> >   }
> >
> > -#ifdef CONFIG_SYS_FSL_DDR
> > -static void ddr_enable_0v9_volt(bool en) -{
> > -	struct ccsr_ddr __iomem *ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR;
> > -	u32 tmp;
> > -
> > -	tmp = ddr_in32(&ddr->ddr_cdr1);
> > -
> > -	if (en)
> > -		tmp |= DDR_CDR1_V0PT9_EN;
> > -	else
> > -		tmp &= ~DDR_CDR1_V0PT9_EN;
> > -
> > -	ddr_out32(&ddr->ddr_cdr1, tmp);
> > -}
> > -#endif
> > -
> >   int setup_chip_volt(void)
> >   {
> >   	int vdd;
> > @@ -485,6 +468,23 @@ void fsl_lsch2_early_init_f(void)
> >   }
> >   #endif
> >
> > +#ifdef CONFIG_SYS_FSL_DDR
> > +void ddr_enable_0v9_volt(bool en)
> > +{
> > +	struct ccsr_ddr __iomem *ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR;
> > +	u32 tmp;
> > +
> > +	tmp = ddr_in32(&ddr->ddr_cdr1);
> > +
> > +	if (en)
> > +		tmp |= DDR_CDR1_V0PT9_EN;
> > +	else
> > +		tmp &= ~DDR_CDR1_V0PT9_EN;
> > +
> > +	ddr_out32(&ddr->ddr_cdr1, tmp);
> > +}
> > +#endif
> > +
> 
> 
> I lost track. When do you use 0.9v for DDR?
> 

When core voltage is set to 0.9v, it requires setting up the DDR controller 
with 0.9 v setting. Prior to this patch, this code was used only in chasis2. 
Making it non-static to use in chasis3 architecture also. 
	
> York


More information about the U-Boot mailing list