[U-Boot] [PATCH v3 1/7] armv8: lsch3: Add serdes and DDR voltage setup
Rajesh Bhagat
rajesh.bhagat at nxp.com
Mon Aug 28 10:26:30 UTC 2017
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
+
+#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);
+
+ 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);
+
+ reg = in_le32(&serdes1_base->bank[i].rstctl);
+ reg |= 0x00000080;
+ out_le32(&serdes1_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(&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);
+ }
+#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
+
+ /* Wait for at atleast 625us, ensure the PLLs being reset are locked */
+ udelay(800);
+
+#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
+
#ifdef CONFIG_QSPI_AHB_INIT
/* Enable 4bytes address support and fast read */
int qspi_ahb_init(void)
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/fsl_serdes.h b/arch/arm/include/asm/arch-fsl-layerscape/fsl_serdes.h
index 12fd6b8..9becdf3 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/fsl_serdes.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/fsl_serdes.h
@@ -164,6 +164,7 @@ void fsl_rgmii_init(void);
#ifdef CONFIG_FSL_LSCH2
const char *serdes_clock_to_string(u32 clock);
int get_serdes_protocol(void);
+#endif
#ifdef CONFIG_SYS_HAS_SERDES
/* Get the volt of SVDD in unit mV */
int get_serdes_volt(void);
@@ -172,6 +173,5 @@ int set_serdes_volt(int svdd);
/* The target volt of SVDD in unit mV */
int setup_serdes_volt(u32 svdd);
#endif
-#endif
#endif /* __FSL_SERDES_H__ */
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h
index ffc5fa2..2706ea8 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h
@@ -370,5 +370,39 @@ struct ccsr_reset {
u32 ip_rev2; /* 0xbfc */
};
+struct ccsr_serdes {
+ struct {
+ u32 rstctl; /* Reset Control Register */
+ u32 pllcr0; /* PLL Control Register 0 */
+ u32 pllcr1; /* PLL Control Register 1 */
+ u32 pllcr2; /* PLL Control Register 2 */
+ u32 pllcr3; /* PLL Control Register 3 */
+ u32 pllcr4; /* PLL Control Register 4 */
+ u32 pllcr5; /* PLL Control Register 5 */
+ u8 res[0x20 - 0x1c];
+ } bank[2];
+ u8 res1[0x90 - 0x40];
+ u32 srdstcalcr; /* TX Calibration Control */
+ u32 srdstcalcr1; /* TX Calibration Control1 */
+ u8 res2[0xa0 - 0x98];
+ u32 srdsrcalcr; /* RX Calibration Control */
+ u32 srdsrcalcr1; /* RX Calibration Control1 */
+ u8 res3[0xb0 - 0xa8];
+ u32 srdsgr0; /* General Register 0 */
+ u8 res4[0x800 - 0xb4];
+ struct serdes_lane {
+ u32 gcr0; /* General Control Register 0 */
+ u32 gcr1; /* General Control Register 1 */
+ u32 gcr2; /* General Control Register 2 */
+ u32 ssc0; /* Speed Switch Control 0 */
+ u32 rec0; /* Receive Equalization Control 0 */
+ u32 rec1; /* Receive Equalization Control 1 */
+ u32 tec0; /* Transmit Equalization Control 0 */
+ u32 ssc1; /* Speed Switch Control 1 */
+ u8 res1[0x840 - 0x820];
+ } lane[8];
+ u8 res5[0x19fc - 0xa00];
+};
+
#endif /*__ASSEMBLY__*/
#endif /* __ARCH_FSL_LSCH3_IMMAP_H_ */
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/soc.h b/arch/arm/include/asm/arch-fsl-layerscape/soc.h
index ea8aced..697f072 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/soc.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/soc.h
@@ -121,6 +121,7 @@ int setup_chip_volt(void);
/* Setup core vdd in unit mV */
int board_setup_core_volt(u32 vdd);
#endif
+void ddr_enable_0v9_volt(bool en);
void cpu_name(char *name);
#ifdef CONFIG_SYS_FSL_ERRATUM_A009635
--
2.7.4
More information about the U-Boot
mailing list