|
@@ -129,6 +129,278 @@ void serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift,
|
|
|
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 *serdes1_base;
|
|
|
+#ifdef CONFIG_SYS_FSL_SRDS_2
|
|
|
+ struct ccsr_serdes *serdes2_base;
|
|
|
+#endif
|
|
|
+ u32 cfg_rcw4 = gur_in32(&gur->rcwsr[4]);
|
|
|
+ u32 cfg_rcw5 = gur_in32(&gur->rcwsr[5]);
|
|
|
+ u32 cfg_tmp, reg = 0;
|
|
|
+ int svdd_cur, svdd_tar;
|
|
|
+ int ret;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ /* Only support switch SVDD to 900mV/1000mV */
|
|
|
+ if (svdd != 900 && svdd != 1000)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ svdd_tar = svdd;
|
|
|
+ svdd_cur = get_serdes_volt();
|
|
|
+ if (svdd_cur < 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ debug("%s: current SVDD: %dmV; target SVDD: %dmV\n",
|
|
|
+ __func__, svdd_cur, svdd_tar);
|
|
|
+ if (svdd_cur == svdd_tar)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ serdes1_base = (void *)CONFIG_SYS_FSL_SERDES_ADDR;
|
|
|
+#ifdef CONFIG_SYS_FSL_SRDS_2
|
|
|
+ serdes2_base = (void *)serdes1_base + 0x10000;
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Put the all enabled lanes in reset */
|
|
|
+#ifdef CONFIG_SYS_FSL_SRDS_1
|
|
|
+ cfg_tmp = cfg_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
|
|
|
+ cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
|
|
|
+
|
|
|
+ for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
|
|
|
+ reg = in_be32(&serdes1_base->lane[i].gcr0);
|
|
|
+ reg &= 0xFF9FFFFF;
|
|
|
+ out_be32(&serdes1_base->lane[i].gcr0, reg);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_SYS_FSL_SRDS_2
|
|
|
+ cfg_tmp = cfg_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_MASK;
|
|
|
+ cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_SHIFT;
|
|
|
+
|
|
|
+ for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
|
|
|
+ reg = in_be32(&serdes2_base->lane[i].gcr0);
|
|
|
+ reg &= 0xFF9FFFFF;
|
|
|
+ out_be32(&serdes2_base->lane[i].gcr0, reg);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Put the all enabled PLL in reset */
|
|
|
+#ifdef CONFIG_SYS_FSL_SRDS_1
|
|
|
+ cfg_tmp = (cfg_rcw5 >> 22) & 0x3;
|
|
|
+ for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
|
|
+ reg = in_be32(&serdes1_base->bank[i].rstctl);
|
|
|
+ reg &= 0xFFFFFFBF;
|
|
|
+ reg |= 0x10000000;
|
|
|
+ out_be32(&serdes1_base->bank[i].rstctl, reg);
|
|
|
+ udelay(1);
|
|
|
+
|
|
|
+ reg = in_be32(&serdes1_base->bank[i].rstctl);
|
|
|
+ reg &= 0xFFFFFF1F;
|
|
|
+ out_be32(&serdes1_base->bank[i].rstctl, reg);
|
|
|
+ }
|
|
|
+ udelay(1);
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef CONFIG_SYS_FSL_SRDS_2
|
|
|
+ cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
|
|
|
+ for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
|
|
+ reg = in_be32(&serdes2_base->bank[i].rstctl);
|
|
|
+ reg &= 0xFFFFFFBF;
|
|
|
+ reg |= 0x10000000;
|
|
|
+ out_be32(&serdes2_base->bank[i].rstctl, reg);
|
|
|
+ udelay(1);
|
|
|
+
|
|
|
+ reg = in_be32(&serdes2_base->bank[i].rstctl);
|
|
|
+ reg &= 0xFFFFFF1F;
|
|
|
+ out_be32(&serdes2_base->bank[i].rstctl, reg);
|
|
|
+ }
|
|
|
+ udelay(1);
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Put the Rx/Tx calibration into reset */
|
|
|
+#ifdef CONFIG_SYS_FSL_SRDS_1
|
|
|
+ reg = in_be32(&serdes1_base->srdstcalcr);
|
|
|
+ reg &= 0xF7FFFFFF;
|
|
|
+ out_be32(&serdes1_base->srdstcalcr, reg);
|
|
|
+ reg = in_be32(&serdes1_base->srdsrcalcr);
|
|
|
+ reg &= 0xF7FFFFFF;
|
|
|
+ out_be32(&serdes1_base->srdsrcalcr, reg);
|
|
|
+
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_SYS_FSL_SRDS_2
|
|
|
+ reg = in_be32(&serdes2_base->srdstcalcr);
|
|
|
+ reg &= 0xF7FFFFFF;
|
|
|
+ out_be32(&serdes2_base->srdstcalcr, reg);
|
|
|
+ reg = in_be32(&serdes2_base->srdsrcalcr);
|
|
|
+ reg &= 0xF7FFFFFF;
|
|
|
+ out_be32(&serdes2_base->srdsrcalcr, reg);
|
|
|
+#endif
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If SVDD set failed, will not return directly, so that the
|
|
|
+ * serdes lanes can complete reseting.
|
|
|
+ */
|
|
|
+ ret = set_serdes_volt(svdd_tar);
|
|
|
+ if (ret)
|
|
|
+ printf("%s: Failed to set SVDD\n", __func__);
|
|
|
+
|
|
|
+ /* Wait for SVDD to stabilize */
|
|
|
+ udelay(100);
|
|
|
+
|
|
|
+ /* For each PLL that’s not disabled via RCW */
|
|
|
+#ifdef CONFIG_SYS_FSL_SRDS_1
|
|
|
+ cfg_tmp = (cfg_rcw5 >> 22) & 0x3;
|
|
|
+ for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
|
|
+ reg = in_be32(&serdes1_base->bank[i].rstctl);
|
|
|
+ reg |= 0x00000020;
|
|
|
+ out_be32(&serdes1_base->bank[i].rstctl, reg);
|
|
|
+ udelay(1);
|
|
|
+
|
|
|
+ reg = in_be32(&serdes1_base->bank[i].rstctl);
|
|
|
+ reg |= 0x00000080;
|
|
|
+ out_be32(&serdes1_base->bank[i].rstctl, reg);
|
|
|
+
|
|
|
+ /* Take the Rx/Tx calibration out of reset */
|
|
|
+ if (!(cfg_tmp == 0x3 && i == 1)) {
|
|
|
+ udelay(1);
|
|
|
+ reg = in_be32(&serdes1_base->srdstcalcr);
|
|
|
+ reg |= 0x08000000;
|
|
|
+ out_be32(&serdes1_base->srdstcalcr, reg);
|
|
|
+ reg = in_be32(&serdes1_base->srdsrcalcr);
|
|
|
+ reg |= 0x08000000;
|
|
|
+ out_be32(&serdes1_base->srdsrcalcr, reg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ udelay(1);
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef CONFIG_SYS_FSL_SRDS_2
|
|
|
+ cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
|
|
|
+ for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
|
|
+ reg = in_be32(&serdes2_base->bank[i].rstctl);
|
|
|
+ reg |= 0x00000020;
|
|
|
+ out_be32(&serdes2_base->bank[i].rstctl, reg);
|
|
|
+ udelay(1);
|
|
|
+
|
|
|
+ reg = in_be32(&serdes2_base->bank[i].rstctl);
|
|
|
+ reg |= 0x00000080;
|
|
|
+ out_be32(&serdes2_base->bank[i].rstctl, reg);
|
|
|
+
|
|
|
+ /* Take the Rx/Tx calibration out of reset */
|
|
|
+ if (!(cfg_tmp == 0x3 && i == 1)) {
|
|
|
+ udelay(1);
|
|
|
+ reg = in_be32(&serdes2_base->srdstcalcr);
|
|
|
+ reg |= 0x08000000;
|
|
|
+ out_be32(&serdes2_base->srdstcalcr, reg);
|
|
|
+ reg = in_be32(&serdes2_base->srdsrcalcr);
|
|
|
+ reg |= 0x08000000;
|
|
|
+ out_be32(&serdes2_base->srdsrcalcr, reg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ udelay(1);
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Wait for at lesat 625us to ensure the PLLs being reset are locked */
|
|
|
+ udelay(800);
|
|
|
+
|
|
|
+#ifdef CONFIG_SYS_FSL_SRDS_1
|
|
|
+ cfg_tmp = (cfg_rcw5 >> 22) & 0x3;
|
|
|
+ for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
|
|
+ /* if the PLL is not locked, set RST_ERR */
|
|
|
+ reg = in_be32(&serdes1_base->bank[i].pllcr0);
|
|
|
+ if (!((reg >> 23) & 0x1)) {
|
|
|
+ reg = in_be32(&serdes1_base->bank[i].rstctl);
|
|
|
+ reg |= 0x20000000;
|
|
|
+ out_be32(&serdes1_base->bank[i].rstctl, reg);
|
|
|
+ } else {
|
|
|
+ udelay(1);
|
|
|
+ reg = in_be32(&serdes1_base->bank[i].rstctl);
|
|
|
+ reg &= 0xFFFFFFEF;
|
|
|
+ reg |= 0x00000040;
|
|
|
+ out_be32(&serdes1_base->bank[i].rstctl, reg);
|
|
|
+ udelay(1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef CONFIG_SYS_FSL_SRDS_2
|
|
|
+ cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
|
|
|
+ for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
|
|
+ reg = in_be32(&serdes2_base->bank[i].pllcr0);
|
|
|
+ if (!((reg >> 23) & 0x1)) {
|
|
|
+ reg = in_be32(&serdes2_base->bank[i].rstctl);
|
|
|
+ reg |= 0x20000000;
|
|
|
+ out_be32(&serdes2_base->bank[i].rstctl, reg);
|
|
|
+ } else {
|
|
|
+ udelay(1);
|
|
|
+ reg = in_be32(&serdes2_base->bank[i].rstctl);
|
|
|
+ reg &= 0xFFFFFFEF;
|
|
|
+ reg |= 0x00000040;
|
|
|
+ out_be32(&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_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
|
|
|
+ cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
|
|
|
+
|
|
|
+ for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
|
|
|
+ reg = in_be32(&serdes1_base->lane[i].gcr0);
|
|
|
+ reg |= 0x00600000;
|
|
|
+ out_be32(&serdes1_base->lane[i].gcr0, reg);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_SYS_FSL_SRDS_2
|
|
|
+ cfg_tmp = cfg_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_MASK;
|
|
|
+ cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_SHIFT;
|
|
|
+
|
|
|
+ for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
|
|
|
+ reg = in_be32(&serdes2_base->lane[i].gcr0);
|
|
|
+ reg |= 0x00600000;
|
|
|
+ out_be32(&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_rcw5 >> 22) & 0x3;
|
|
|
+ for (i = 0; i < 2; i++) {
|
|
|
+ reg = in_be32(&serdes1_base->bank[i].pllcr0);
|
|
|
+ if (!(cfg_tmp & (0x1 << (1 - i))) && ((reg >> 23) & 0x1)) {
|
|
|
+ reg = in_be32(&serdes1_base->bank[i].rstctl);
|
|
|
+ reg |= 0x40000000;
|
|
|
+ out_be32(&serdes1_base->bank[i].rstctl, reg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_SYS_FSL_SRDS_2
|
|
|
+ cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
|
|
|
+ for (i = 0; i < 2; i++) {
|
|
|
+ reg = in_be32(&serdes2_base->bank[i].pllcr0);
|
|
|
+ if (!(cfg_tmp & (0x1 << (1 - i))) && ((reg >> 23) & 0x1)) {
|
|
|
+ reg = in_be32(&serdes2_base->bank[i].rstctl);
|
|
|
+ reg |= 0x40000000;
|
|
|
+ out_be32(&serdes2_base->bank[i].rstctl, reg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
void fsl_serdes_init(void)
|
|
|
{
|
|
|
#ifdef CONFIG_SYS_FSL_SRDS_1
|