@@ -1161,7 +1161,6 @@ static int rtpcs_93xx_sds_set_pll_config(struct rtpcs_serdes *sds, enum rtpcs_sd
11611161 * LC PLL. As it is unclear if disabling PLLs has any positive or negative effect,
11621162 * always activate both.
11631163 */
1164-
11651164 ret = rtpcs_sds_write_bits (even_sds , 0x20 , 0x12 , 3 , 0 , 0xf );
11661165 if (ret < 0 )
11671166 return ret ;
@@ -1186,47 +1185,56 @@ static int rtpcs_93xx_sds_config_cmu(struct rtpcs_serdes *sds, enum rtpcs_sds_mo
11861185 int ret ;
11871186
11881187 /*
1189- * A SerDes pair on the RTL930x is driven by two PLLs. A low speed ring PLL can generate
1190- * signals of 1.25G and 3.125G for link speeds of 1G/2.5G. A high speed LC PLL can
1191- * additionally generate a 10.3125G signal for 10G speeds. To drive the pair at different
1192- * speeds each SerDes must use its own PLL. But what if the SerDess attached to the ring
1193- * PLL suddenly needs 10G but the LC PLL is running at 1G? To avoid reconfiguring the
1194- * "partner" SerDes we must choose wisely what assignment serves the current needs. The
1195- * logic boils down to the following rules:
1188+ * A SerDes pair on RTL93xx is driven by a shared CMU with two PLLs:
1189+ *
1190+ * - a low speed ring PLL which can generate signals of 1.25G and 3.125G for link
1191+ * speeds of 1G/2.5G
1192+ * - a high speed LC PLL which can additionally generate a 10.3125G signal for
1193+ * 10G link speeds
1194+ *
1195+ * To drive the pair at different speeds, each SerDes must use its own PLL and we
1196+ * must wisely assign the PLLs to the SerDes based on their needs. The logic boils
1197+ * down to the following rules:
11961198 *
1197- * - Use ring PLL for slow 1G speeds
1198- * - Use LC PLL for fast 10G speeds
1199- * - For 2.5G prefer ring over LC PLL
1199+ * - use ring PLL for slow 1G speeds
1200+ * - use LC PLL for fast 10G speeds
1201+ * - for 2.5G prefer ring over LC PLL
12001202 *
1201- * However, when we want to configure 10G speed while the other SerDes is already using
1202- * the LC PLL for a slower speed, there is no way to avoid reconfiguration. Note that
1203- * this can even happen when the other SerDes is not actually in use, because changing
1204- * the state of a SerDes back to RTL930X_SDS_OFF is not (yet) implemented.
1203+ * For the case that we want to configure 10G speed but the LC PLL is already used
1204+ * by the neighbor SerDes and running with a slower speed, there's no way to avoid
1205+ * reconfiguration. The neighbor SerDes is reconfigured online to the ring PLL.
12051206 */
12061207
1207- ret = nb_sds -> ops -> get_pll_select (nb_sds , & neighbor_pll );
1208+ if (hw_mode == RTPCS_SDS_MODE_OFF )
1209+ return 0 ;
1210+
1211+ ret = rtpcs_sds_select_pll_speed (hw_mode , & speed );
12081212 if (ret < 0 )
12091213 return ret ;
12101214
1211- ret = rtpcs_93xx_sds_get_pll_config (nb_sds , neighbor_pll , & neighbor_speed );
1215+ if (nb_sds -> hw_mode == RTPCS_SDS_MODE_OFF ) {
1216+ pll = (speed == RTPCS_SDS_PLL_SPD_10000 ) ? RTPCS_SDS_PLL_TYPE_LC
1217+ : RTPCS_SDS_PLL_TYPE_RING ;
1218+ goto pll_setup ;
1219+ }
1220+
1221+ ret = nb_sds -> ops -> get_pll_select (nb_sds , & neighbor_pll );
12121222 if (ret < 0 )
12131223 return ret ;
12141224
1215- ret = rtpcs_sds_select_pll_speed ( hw_mode , & speed );
1225+ ret = rtpcs_93xx_sds_get_pll_config ( nb_sds , neighbor_pll , & neighbor_speed );
12161226 if (ret < 0 )
12171227 return ret ;
12181228
1219- if (nb_sds -> hw_mode == RTPCS_SDS_MODE_OFF )
1220- pll = speed == RTPCS_SDS_PLL_SPD_10000 ? RTPCS_SDS_PLL_TYPE_LC
1221- : RTPCS_SDS_PLL_TYPE_RING ;
1222- else if (speed == neighbor_speed ) {
1229+ if (speed == neighbor_speed ) {
12231230 speed_changed = false;
12241231 pll = neighbor_pll ;
12251232 } else if (neighbor_pll == RTPCS_SDS_PLL_TYPE_RING )
12261233 pll = RTPCS_SDS_PLL_TYPE_LC ;
12271234 else if (speed == RTPCS_SDS_PLL_SPD_10000 ) {
12281235 pr_info ("%s: SDS %d needs LC PLL, reconfigure SDS %d to use ring PLL\n" ,
12291236 __func__ , sds -> id , nb_sds -> id );
1237+
12301238 ret = nb_sds -> ops -> reconfigure_to_pll (nb_sds , RTPCS_SDS_PLL_TYPE_RING );
12311239 if (ret < 0 )
12321240 return ret ;
@@ -1235,16 +1243,19 @@ static int rtpcs_93xx_sds_config_cmu(struct rtpcs_serdes *sds, enum rtpcs_sds_mo
12351243 } else
12361244 pll = RTPCS_SDS_PLL_TYPE_RING ;
12371245
1238- if (speed_changed )
1246+ pll_setup :
1247+ if (speed_changed ) {
12391248 ret = rtpcs_93xx_sds_set_pll_config (sds , pll , speed );
1249+ if (ret < 0 )
1250+ return ret ;
1251+ }
12401252
12411253 ret = sds -> ops -> set_pll_select (sds , hw_mode , pll );
12421254 if (ret < 0 )
12431255 return ret ;
12441256
12451257 pr_info ("%s: SDS %d using %s PLL for mode %d\n" , __func__ , sds -> id ,
12461258 pll == RTPCS_SDS_PLL_TYPE_LC ? "LC" : "ring" , hw_mode );
1247-
12481259 return ret ;
12491260}
12501261
0 commit comments