* LC PLL. As it is unclear if disabling PLLs has any positive or negative effect,
* always activate both.
*/
-
ret = rtpcs_sds_write_bits(even_sds, 0x20, 0x12, 3, 0, 0xf);
if (ret < 0)
return ret;
int ret;
/*
- * A SerDes pair on the RTL930x is driven by two PLLs. A low speed ring PLL can generate
- * signals of 1.25G and 3.125G for link speeds of 1G/2.5G. A high speed LC PLL can
- * additionally generate a 10.3125G signal for 10G speeds. To drive the pair at different
- * speeds each SerDes must use its own PLL. But what if the SerDess attached to the ring
- * PLL suddenly needs 10G but the LC PLL is running at 1G? To avoid reconfiguring the
- * "partner" SerDes we must choose wisely what assignment serves the current needs. The
- * logic boils down to the following rules:
+ * A SerDes pair on RTL93xx is driven by a shared CMU with two PLLs:
+ *
+ * - a low speed ring PLL which can generate signals of 1.25G and 3.125G for link
+ * speeds of 1G/2.5G
+ * - a high speed LC PLL which can additionally generate a 10.3125G signal for
+ * 10G link speeds
+ *
+ * To drive the pair at different speeds, each SerDes must use its own PLL and we
+ * must wisely assign the PLLs to the SerDes based on their needs. The logic boils
+ * down to the following rules:
*
- * - Use ring PLL for slow 1G speeds
- * - Use LC PLL for fast 10G speeds
- * - For 2.5G prefer ring over LC PLL
+ * - use ring PLL for slow 1G speeds
+ * - use LC PLL for fast 10G speeds
+ * - for 2.5G prefer ring over LC PLL
*
- * However, when we want to configure 10G speed while the other SerDes is already using
- * the LC PLL for a slower speed, there is no way to avoid reconfiguration. Note that
- * this can even happen when the other SerDes is not actually in use, because changing
- * the state of a SerDes back to RTL930X_SDS_OFF is not (yet) implemented.
+ * For the case that we want to configure 10G speed but the LC PLL is already used
+ * by the neighbor SerDes and running with a slower speed, there's no way to avoid
+ * reconfiguration. The neighbor SerDes is reconfigured online to the ring PLL.
*/
- ret = nb_sds->ops->get_pll_select(nb_sds, &neighbor_pll);
+ if (hw_mode == RTPCS_SDS_MODE_OFF)
+ return 0;
+
+ ret = rtpcs_sds_select_pll_speed(hw_mode, &speed);
if (ret < 0)
return ret;
- ret = rtpcs_93xx_sds_get_pll_config(nb_sds, neighbor_pll, &neighbor_speed);
+ if (nb_sds->hw_mode == RTPCS_SDS_MODE_OFF) {
+ pll = (speed == RTPCS_SDS_PLL_SPD_10000) ? RTPCS_SDS_PLL_TYPE_LC
+ : RTPCS_SDS_PLL_TYPE_RING;
+ goto pll_setup;
+ }
+
+ ret = nb_sds->ops->get_pll_select(nb_sds, &neighbor_pll);
if (ret < 0)
return ret;
- ret = rtpcs_sds_select_pll_speed(hw_mode, &speed);
+ ret = rtpcs_93xx_sds_get_pll_config(nb_sds, neighbor_pll, &neighbor_speed);
if (ret < 0)
return ret;
- if (nb_sds->hw_mode == RTPCS_SDS_MODE_OFF)
- pll = speed == RTPCS_SDS_PLL_SPD_10000 ? RTPCS_SDS_PLL_TYPE_LC
- : RTPCS_SDS_PLL_TYPE_RING;
- else if (speed == neighbor_speed) {
+ if (speed == neighbor_speed) {
speed_changed = false;
pll = neighbor_pll;
} else if (neighbor_pll == RTPCS_SDS_PLL_TYPE_RING)
else if (speed == RTPCS_SDS_PLL_SPD_10000) {
pr_info("%s: SDS %d needs LC PLL, reconfigure SDS %d to use ring PLL\n",
__func__, sds->id, nb_sds->id);
+
ret = nb_sds->ops->reconfigure_to_pll(nb_sds, RTPCS_SDS_PLL_TYPE_RING);
if (ret < 0)
return ret;
} else
pll = RTPCS_SDS_PLL_TYPE_RING;
- if (speed_changed)
+pll_setup:
+ if (speed_changed) {
ret = rtpcs_93xx_sds_set_pll_config(sds, pll, speed);
+ if (ret < 0)
+ return ret;
+ }
ret = sds->ops->set_pll_select(sds, hw_mode, pll);
if (ret < 0)
pr_info("%s: SDS %d using %s PLL for mode %d\n", __func__, sds->id,
pll == RTPCS_SDS_PLL_TYPE_LC ? "LC" : "ring", hw_mode);
-
return ret;
}