[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