Skip to content

Commit eccb5c6

Browse files
jonasjelonekhauke
authored andcommitted
realtek: pcs: make rtl930x CMU config generic
Generalize the RTL930x CMU configuration to support RTL931x as well. Both implementations differ only in minor details, allowing them to share common code and avoid duplication. Affected functions are moved up in the code to the 93xx common area and slightly renamed. Existing variant-specific functions are adjusted too and assigned to the previously added SerDes operation hooks. Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com> Link: openwrt/openwrt#22198 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
1 parent 8e29b78 commit eccb5c6

1 file changed

Lines changed: 137 additions & 137 deletions

File tree

target/linux/realtek/files-6.12/drivers/net/pcs/pcs-rtl-otto.c

Lines changed: 137 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,6 +1119,135 @@ static int rtpcs_93xx_init_serdes_common(struct rtpcs_ctrl *ctrl)
11191119
return 0;
11201120
}
11211121

1122+
static int rtpcs_93xx_sds_get_pll_config(struct rtpcs_serdes *sds, enum rtpcs_sds_pll_type pll,
1123+
enum rtpcs_sds_pll_speed *speed)
1124+
{
1125+
struct rtpcs_serdes *even_sds = rtpcs_sds_get_even(sds);
1126+
int sbit, speed_val;
1127+
1128+
/*
1129+
* PLL config is shared between adjacent SerDes in the even lane. Each SerDes defines
1130+
* what PLL it needs (ring or LC) while the PLL itself stores the current speed.
1131+
*/
1132+
1133+
sbit = pll == RTPCS_SDS_PLL_TYPE_LC ? 8 : 12;
1134+
speed_val = rtpcs_sds_read_bits(even_sds, 0x20, 0x12, sbit + 3, sbit);
1135+
if (speed_val < 0)
1136+
return speed_val;
1137+
1138+
/* bit 0 is force-bit, bits [3:1] are speed selector */
1139+
*speed = (enum rtpcs_sds_pll_speed)(speed_val >> 1);
1140+
return 0;
1141+
}
1142+
1143+
static int rtpcs_93xx_sds_set_pll_config(struct rtpcs_serdes *sds, enum rtpcs_sds_pll_type pll,
1144+
enum rtpcs_sds_pll_speed speed)
1145+
{
1146+
struct rtpcs_serdes *even_sds = rtpcs_sds_get_even(sds);
1147+
int sbit = pll == RTPCS_SDS_PLL_TYPE_LC ? 8 : 12;
1148+
int ret;
1149+
1150+
if (speed >= RTPCS_SDS_PLL_SPD_END)
1151+
return -EINVAL;
1152+
1153+
if (pll >= RTPCS_SDS_PLL_TYPE_END)
1154+
return -EINVAL;
1155+
1156+
if ((pll == RTPCS_SDS_PLL_TYPE_RING) && (speed == RTPCS_SDS_PLL_SPD_10000))
1157+
return -EINVAL;
1158+
1159+
/*
1160+
* A SerDes clock can either be taken from the low speed ring PLL or the high speed
1161+
* LC PLL. As it is unclear if disabling PLLs has any positive or negative effect,
1162+
* always activate both.
1163+
*/
1164+
1165+
ret = rtpcs_sds_write_bits(even_sds, 0x20, 0x12, 3, 0, 0xf);
1166+
if (ret < 0)
1167+
return ret;
1168+
1169+
/* bit 0 is force-bit, bits [3:1] are speed selector */
1170+
ret = rtpcs_sds_write_bits(even_sds, 0x20, 0x12, sbit + 3, sbit, (speed << 1) | BIT(0));
1171+
if (ret < 0)
1172+
return ret;
1173+
1174+
if (sds->ops->reset_cmu)
1175+
ret = sds->ops->reset_cmu(sds, pll);
1176+
1177+
return ret;
1178+
}
1179+
1180+
static int rtpcs_93xx_sds_config_cmu(struct rtpcs_serdes *sds, enum rtpcs_sds_mode hw_mode)
1181+
{
1182+
struct rtpcs_serdes *nb_sds = rtpcs_sds_get_neighbor(sds);
1183+
enum rtpcs_sds_pll_speed speed, neighbor_speed;
1184+
enum rtpcs_sds_pll_type pll, neighbor_pll;
1185+
bool speed_changed = true;
1186+
int ret;
1187+
1188+
/*
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:
1196+
*
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
1200+
*
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.
1205+
*/
1206+
1207+
ret = nb_sds->ops->get_pll_select(nb_sds, &neighbor_pll);
1208+
if (ret < 0)
1209+
return ret;
1210+
1211+
ret = rtpcs_93xx_sds_get_pll_config(nb_sds, neighbor_pll, &neighbor_speed);
1212+
if (ret < 0)
1213+
return ret;
1214+
1215+
ret = rtpcs_sds_select_pll_speed(hw_mode, &speed);
1216+
if (ret < 0)
1217+
return ret;
1218+
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) {
1223+
speed_changed = false;
1224+
pll = neighbor_pll;
1225+
} else if (neighbor_pll == RTPCS_SDS_PLL_TYPE_RING)
1226+
pll = RTPCS_SDS_PLL_TYPE_LC;
1227+
else if (speed == RTPCS_SDS_PLL_SPD_10000) {
1228+
pr_info("%s: SDS %d needs LC PLL, reconfigure SDS %d to use ring PLL\n",
1229+
__func__, sds->id, nb_sds->id);
1230+
ret = nb_sds->ops->reconfigure_to_pll(nb_sds, RTPCS_SDS_PLL_TYPE_RING);
1231+
if (ret < 0)
1232+
return ret;
1233+
1234+
pll = RTPCS_SDS_PLL_TYPE_LC;
1235+
} else
1236+
pll = RTPCS_SDS_PLL_TYPE_RING;
1237+
1238+
if (speed_changed)
1239+
ret = rtpcs_93xx_sds_set_pll_config(sds, pll, speed);
1240+
1241+
ret = sds->ops->set_pll_select(sds, hw_mode, pll);
1242+
if (ret < 0)
1243+
return ret;
1244+
1245+
pr_info("%s: SDS %d using %s PLL for mode %d\n", __func__, sds->id,
1246+
pll == RTPCS_SDS_PLL_TYPE_LC ? "LC" : "ring", hw_mode);
1247+
1248+
return ret;
1249+
}
1250+
11221251
/* RTL930X */
11231252

11241253
/*
@@ -1290,27 +1419,6 @@ static int rtpcs_930x_sds_get_pll_select(struct rtpcs_serdes *sds, enum rtpcs_sd
12901419
return 0;
12911420
}
12921421

1293-
static int rtpcs_930x_sds_get_pll_config(struct rtpcs_serdes *sds, enum rtpcs_sds_pll_type pll,
1294-
enum rtpcs_sds_pll_speed *speed)
1295-
{
1296-
struct rtpcs_serdes *even_sds = rtpcs_sds_get_even(sds);
1297-
int sbit, speed_val;
1298-
1299-
/*
1300-
* PLL data is shared between adjacent SerDes in the even lane. Each SerDes defines
1301-
* what PLL it needs (ring or LC) while the PLL itself stores the current speed.
1302-
*/
1303-
1304-
sbit = pll == RTPCS_SDS_PLL_TYPE_LC ? 8 : 12;
1305-
speed_val = rtpcs_sds_read_bits(even_sds, 0x20, 0x12, sbit + 3, sbit);
1306-
if (speed_val < 0)
1307-
return speed_val;
1308-
1309-
/* bit 0 is force-bit, bits [3:1] are speed selector */
1310-
*speed = (enum rtpcs_sds_pll_speed)(speed_val >> 1);
1311-
return 0;
1312-
}
1313-
13141422
static int rtpcs_930x_sds_set_pll_select(struct rtpcs_serdes *sds, enum rtpcs_sds_mode hw_mode,
13151423
enum rtpcs_sds_pll_type pll)
13161424
{
@@ -1323,21 +1431,17 @@ static int rtpcs_930x_sds_set_pll_select(struct rtpcs_serdes *sds, enum rtpcs_sd
13231431
return rtpcs_sds_write_bits(even_sds, 0x20, 0x12, pbit + 1, pbit, (pll << 1) | BIT(0));
13241432
}
13251433

1326-
static int rtpcs_930x_sds_reset_cmu(struct rtpcs_serdes *sds)
1434+
static int rtpcs_930x_sds_reset_cmu(struct rtpcs_serdes *sds, enum rtpcs_sds_pll_type pll)
13271435
{
13281436
struct rtpcs_serdes *even_sds = rtpcs_sds_get_even(sds);
13291437
int reset_sequence[4] = { 3, 2, 3, 1 };
1330-
enum rtpcs_sds_pll_type pll;
13311438
int bit, i, ret;
13321439

13331440
/*
13341441
* After the PLL speed has changed, the CMU must take over the new values. The models
13351442
* of the Otto platform have different reset sequences. Luckily it always boils down
13361443
* to flipping two bits in a special sequence.
13371444
*/
1338-
ret = rtpcs_930x_sds_get_pll_select(sds, &pll);
1339-
if (ret < 0)
1340-
return ret;
13411445

13421446
bit = pll == RTPCS_SDS_PLL_TYPE_LC ? 2 : 0;
13431447

@@ -1350,40 +1454,6 @@ static int rtpcs_930x_sds_reset_cmu(struct rtpcs_serdes *sds)
13501454
return 0;
13511455
}
13521456

1353-
static int rtpcs_930x_sds_set_pll_config(struct rtpcs_serdes *sds, enum rtpcs_sds_pll_type pll,
1354-
enum rtpcs_sds_pll_speed speed)
1355-
{
1356-
struct rtpcs_serdes *even_sds = rtpcs_sds_get_even(sds);
1357-
int sbit = pll == RTPCS_SDS_PLL_TYPE_LC ? 8 : 12;
1358-
int ret;
1359-
1360-
if (speed >= RTPCS_SDS_PLL_SPD_END)
1361-
return -EINVAL;
1362-
1363-
if (pll >= RTPCS_SDS_PLL_TYPE_END)
1364-
return -EINVAL;
1365-
1366-
if ((pll == RTPCS_SDS_PLL_TYPE_RING) && (speed == RTPCS_SDS_PLL_SPD_10000))
1367-
return -EINVAL;
1368-
1369-
/*
1370-
* A SerDes clock can either be taken from the low speed ring PLL or the high speed
1371-
* LC PLL. As it is unclear if disabling PLLs has any positive or negative effect,
1372-
* always activate both.
1373-
*/
1374-
1375-
ret = rtpcs_sds_write_bits(even_sds, 0x20, 0x12, 3, 0, 0xf);
1376-
if (ret < 0)
1377-
return ret;
1378-
1379-
/* bit 0 is force-bit, bits [3:1] are speed selector */
1380-
ret = rtpcs_sds_write_bits(even_sds, 0x20, 0x12, sbit + 3, sbit, (speed << 1) | BIT(0));
1381-
if (ret < 0)
1382-
return ret;
1383-
1384-
return rtpcs_930x_sds_reset_cmu(sds);
1385-
}
1386-
13871457
static int rtpcs_930x_sds_wait_clock_ready(struct rtpcs_serdes *sds)
13881458
{
13891459
struct rtpcs_serdes *even_sds = rtpcs_sds_get_even(sds);
@@ -1441,14 +1511,14 @@ static int rtpcs_930x_sds_reconfigure_to_pll(struct rtpcs_serdes *sds, enum rtpc
14411511
if (ret < 0)
14421512
return ret;
14431513

1444-
ret = rtpcs_930x_sds_get_pll_config(sds, old_pll, &speed);
1514+
ret = rtpcs_93xx_sds_get_pll_config(sds, old_pll, &speed);
14451515
if (ret < 0)
14461516
return ret;
14471517

14481518
rtpcs_930x_sds_set_power(sds, false);
14491519
__rtpcs_930x_sds_set_ip_mode(sds, RTPCS_930X_SDS_OFF);
14501520

1451-
ret = rtpcs_930x_sds_set_pll_config(sds, pll, speed);
1521+
ret = rtpcs_93xx_sds_set_pll_config(sds, pll, speed);
14521522
if (ret < 0)
14531523
return ret;
14541524

@@ -1464,80 +1534,6 @@ static int rtpcs_930x_sds_reconfigure_to_pll(struct rtpcs_serdes *sds, enum rtpc
14641534
return 0;
14651535
}
14661536

1467-
static int rtpcs_930x_sds_config_cmu(struct rtpcs_serdes *sds,
1468-
enum rtpcs_sds_mode hw_mode)
1469-
{
1470-
struct rtpcs_serdes *nb_sds = rtpcs_sds_get_neighbor(sds);
1471-
enum rtpcs_sds_pll_speed speed, neighbor_speed;
1472-
enum rtpcs_sds_pll_type pll, neighbor_pll;
1473-
bool speed_changed = true;
1474-
int neighbor_mode, ret;
1475-
1476-
/*
1477-
* A SerDes pair on the RTL930x is driven by two PLLs. A low speed ring PLL can generate
1478-
* signals of 1.25G and 3.125G for link speeds of 1G/2.5G. A high speed LC PLL can
1479-
* additionally generate a 10.3125G signal for 10G speeds. To drive the pair at different
1480-
* speeds each SerDes must use its own PLL. But what if the SerDess attached to the ring
1481-
* PLL suddenly needs 10G but the LC PLL is running at 1G? To avoid reconfiguring the
1482-
* "partner" SerDes we must choose wisely what assignment serves the current needs. The
1483-
* logic boils down to the following rules:
1484-
*
1485-
* - Use ring PLL for slow 1G speeds
1486-
* - Use LC PLL for fast 10G speeds
1487-
* - For 2.5G prefer ring over LC PLL
1488-
*
1489-
* However, when we want to configure 10G speed while the other SerDes is already using
1490-
* the LC PLL for a slower speed, there is no way to avoid reconfiguration. Note that
1491-
* this can even happen when the other SerDes is not actually in use, because changing
1492-
* the state of a SerDes back to RTL930X_SDS_OFF is not (yet) implemented.
1493-
*/
1494-
1495-
neighbor_mode = __rtpcs_930x_sds_get_ip_mode(nb_sds);
1496-
1497-
ret = rtpcs_930x_sds_get_pll_select(sds, &neighbor_pll);
1498-
if (ret < 0)
1499-
return ret;
1500-
1501-
ret = rtpcs_930x_sds_get_pll_config(nb_sds, neighbor_pll, &neighbor_speed);
1502-
if (ret < 0)
1503-
return ret;
1504-
1505-
ret = rtpcs_sds_select_pll_speed(hw_mode, &speed);
1506-
if (ret < 0)
1507-
return ret;
1508-
1509-
if (!neighbor_mode)
1510-
pll = speed == RTPCS_SDS_PLL_SPD_10000 ? RTPCS_SDS_PLL_TYPE_LC
1511-
: RTPCS_SDS_PLL_TYPE_RING;
1512-
else if (speed == neighbor_speed) {
1513-
speed_changed = false;
1514-
pll = neighbor_pll;
1515-
} else if (neighbor_pll == RTPCS_SDS_PLL_TYPE_RING)
1516-
pll = RTPCS_SDS_PLL_TYPE_LC;
1517-
else if (speed == RTPCS_SDS_PLL_SPD_10000) {
1518-
pr_info("%s: SDS %d needs LC PLL, reconfigure SDS %d to use ring PLL\n",
1519-
__func__, sds->id, nb_sds->id);
1520-
ret = rtpcs_930x_sds_reconfigure_to_pll(nb_sds, RTPCS_SDS_PLL_TYPE_RING);
1521-
if (ret < 0)
1522-
return ret;
1523-
1524-
pll = RTPCS_SDS_PLL_TYPE_LC;
1525-
} else
1526-
pll = RTPCS_SDS_PLL_TYPE_RING;
1527-
1528-
if (speed_changed)
1529-
ret = rtpcs_930x_sds_set_pll_config(sds, pll, speed);
1530-
1531-
ret = rtpcs_930x_sds_set_pll_select(sds, hw_mode, pll);
1532-
if (ret < 0)
1533-
return ret;
1534-
1535-
pr_info("%s: SDS %d using %s PLL for mode %d\n", __func__, sds->id,
1536-
pll == RTPCS_SDS_PLL_TYPE_LC ? "LC" : "ring", hw_mode);
1537-
1538-
return ret;
1539-
}
1540-
15411537
static void rtpcs_930x_sds_reset_state_machine(struct rtpcs_serdes *sds)
15421538
{
15431539
rtpcs_sds_write_bits(sds, 0x06, 0x02, 12, 12, 0x01); /* SM_RESET bit */
@@ -1627,7 +1623,7 @@ static int rtpcs_930x_sds_set_ip_mode(struct rtpcs_serdes *sds,
16271623
if (hw_mode == RTPCS_SDS_MODE_OFF)
16281624
return 0;
16291625

1630-
ret = rtpcs_930x_sds_config_cmu(sds, hw_mode);
1626+
ret = rtpcs_93xx_sds_config_cmu(sds, hw_mode);
16311627
if (ret < 0)
16321628
pr_err("%s: SDS %d could not configure PLL for mode %d: %d\n", __func__,
16331629
sds->id, hw_mode, ret);
@@ -4300,6 +4296,10 @@ static const struct rtpcs_serdes_ops rtpcs_930x_sds_ops = {
43004296
.xsg_write = rtpcs_930x_sds_op_xsg_write,
43014297
.set_autoneg = rtpcs_93xx_sds_set_autoneg,
43024298
.restart_autoneg = rtpcs_generic_sds_restart_autoneg,
4299+
.get_pll_select = rtpcs_930x_sds_get_pll_select,
4300+
.set_pll_select = rtpcs_930x_sds_set_pll_select,
4301+
.reset_cmu = rtpcs_930x_sds_reset_cmu,
4302+
.reconfigure_to_pll = rtpcs_930x_sds_reconfigure_to_pll,
43034303
};
43044304

43054305
static const struct rtpcs_sds_regs rtpcs_930x_sds_regs = {

0 commit comments

Comments
 (0)