diff --git a/target/linux/realtek/files-6.12/drivers/net/pcs/pcs-rtl-otto.c b/target/linux/realtek/files-6.12/drivers/net/pcs/pcs-rtl-otto.c index bbc0167153..d26b4aab80 100644 --- a/target/linux/realtek/files-6.12/drivers/net/pcs/pcs-rtl-otto.c +++ b/target/linux/realtek/files-6.12/drivers/net/pcs/pcs-rtl-otto.c @@ -410,6 +410,26 @@ static void rtpcs_930x_sds_set_power(struct rtpcs_ctrl *ctrl, int sds, bool on) rtpcs_sds_write_bits(ctrl, sds, 0x20, 0x00, 5, 4, rx_enable); } +static void rtpcs_930x_sds_reconfigure_pll(struct rtpcs_ctrl *ctrl, int sds, int pll) +{ + int mode, tmp, speed; + + mode = rtpcs_930x_sds_get_internal_mode(ctrl, sds); + rtpcs_930x_sds_get_pll_data(ctrl, sds, &tmp, &speed); + + rtpcs_930x_sds_set_power(ctrl, sds, false); + rtpcs_930x_sds_set_internal_mode(ctrl, sds, RTL930X_SDS_OFF); + + rtpcs_930x_sds_set_pll_data(ctrl, sds, pll, speed); + rtpcs_930x_sds_reset_cmu(ctrl, sds); + + rtpcs_930x_sds_set_internal_mode(ctrl, sds, mode); + if (rtpcs_930x_sds_wait_clock_ready(ctrl, sds)) + pr_err("%s: SDS %d could not sync clock\n", __func__, sds); + + rtpcs_930x_sds_set_power(ctrl, sds, true); +} + static int rtpcs_930x_sds_config_pll(struct rtpcs_ctrl *ctrl, int sds, phy_interface_t interface) { @@ -429,6 +449,11 @@ static int rtpcs_930x_sds_config_pll(struct rtpcs_ctrl *ctrl, int sds, * - 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. */ neighbor_mode = rtpcs_930x_sds_get_internal_mode(ctrl, neighbor); @@ -451,9 +476,12 @@ static int rtpcs_930x_sds_config_pll(struct rtpcs_ctrl *ctrl, int sds, pll = neighbor_pll; } else if (neighbor_pll == RTSDS_930X_PLL_RING) pll = RTSDS_930X_PLL_LC; - else if (speed == RTSDS_930X_PLL_10000) - return -ENOTSUPP; /* caller wants 10G but only ring PLL available */ - else + else if (speed == RTSDS_930X_PLL_10000) { + pr_info("%s: SDS %d needs LC PLL, reconfigure SDS %d to use ring PLL\n", + __func__, sds, neighbor); + rtpcs_930x_sds_reconfigure_pll(ctrl, neighbor, RTSDS_930X_PLL_RING); + pll = RTSDS_930X_PLL_LC; + } else pll = RTSDS_930X_PLL_RING; rtpcs_930x_sds_set_pll_data(ctrl, sds, pll, speed);