Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

phy: cadence: Sierra: Add support for skipping configuration

In some cases, a single SerDes instance can be shared between two different
processors, each using a separate link. In these cases, the SerDes
configuration is done in an earlier boot stage. Therefore, add support to
skip reconfiguring, if it is was already configured beforehand.

Signed-off-by: Aswath Govindraju <a-govindraju@ti.com>
Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com>
Link: https://lore.kernel.org/r/20220128072642.29188-1-a-govindraju@ti.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Aswath Govindraju and committed by
Vinod Koul
d88ca22d 1e805d19

+57 -25
+57 -25
drivers/phy/cadence/phy-cadence-sierra.c
··· 370 370 int nsubnodes; 371 371 u32 num_lanes; 372 372 bool autoconf; 373 + int already_configured; 373 374 struct clk_onecell_data clk_data; 374 375 struct clk *output_clks[CDNS_SIERRA_OUTPUT_CLOCKS]; 375 376 }; ··· 518 517 int i, j; 519 518 520 519 /* Initialise the PHY registers, unless auto configured */ 521 - if (phy->autoconf || phy->nsubnodes > 1) 520 + if (phy->autoconf || phy->already_configured || phy->nsubnodes > 1) 522 521 return 0; 523 522 524 523 clk_set_rate(phy->input_clks[CMN_REFCLK_DIG_DIV], 25000000); ··· 644 643 .power_on = cdns_sierra_phy_on, 645 644 .power_off = cdns_sierra_phy_off, 646 645 .reset = cdns_sierra_phy_reset, 646 + .owner = THIS_MODULE, 647 + }; 648 + 649 + static int cdns_sierra_noop_phy_on(struct phy *gphy) 650 + { 651 + usleep_range(5000, 10000); 652 + 653 + return 0; 654 + } 655 + 656 + static const struct phy_ops noop_ops = { 657 + .power_on = cdns_sierra_noop_phy_on, 647 658 .owner = THIS_MODULE, 648 659 }; 649 660 ··· 1131 1118 struct clk *clk; 1132 1119 int ret; 1133 1120 1134 - clk = devm_clk_get_optional(dev, "phy_clk"); 1135 - if (IS_ERR(clk)) { 1136 - dev_err(dev, "failed to get clock phy_clk\n"); 1137 - return PTR_ERR(clk); 1138 - } 1139 - sp->input_clks[PHY_CLK] = clk; 1140 - 1141 1121 clk = devm_clk_get_optional(dev, "cmn_refclk_dig_div"); 1142 1122 if (IS_ERR(clk)) { 1143 1123 dev_err(dev, "cmn_refclk_dig_div clock not found\n"); ··· 1166 1160 return 0; 1167 1161 } 1168 1162 1169 - static int cdns_sierra_phy_enable_clocks(struct cdns_sierra_phy *sp) 1163 + static int cdns_sierra_phy_clk(struct cdns_sierra_phy *sp) 1170 1164 { 1165 + struct device *dev = sp->dev; 1166 + struct clk *clk; 1171 1167 int ret; 1168 + 1169 + clk = devm_clk_get_optional(dev, "phy_clk"); 1170 + if (IS_ERR(clk)) { 1171 + dev_err(dev, "failed to get clock phy_clk\n"); 1172 + return PTR_ERR(clk); 1173 + } 1174 + sp->input_clks[PHY_CLK] = clk; 1172 1175 1173 1176 ret = clk_prepare_enable(sp->input_clks[PHY_CLK]); 1174 1177 if (ret) 1175 1178 return ret; 1176 1179 1180 + return 0; 1181 + } 1182 + 1183 + static int cdns_sierra_phy_enable_clocks(struct cdns_sierra_phy *sp) 1184 + { 1185 + int ret; 1186 + 1177 1187 ret = clk_prepare_enable(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]); 1178 1188 if (ret) 1179 - goto err_pll_cmnlc; 1189 + return ret; 1180 1190 1181 1191 ret = clk_prepare_enable(sp->output_clks[CDNS_SIERRA_PLL_CMNLC1]); 1182 1192 if (ret) ··· 1203 1181 err_pll_cmnlc1: 1204 1182 clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]); 1205 1183 1206 - err_pll_cmnlc: 1207 - clk_disable_unprepare(sp->input_clks[PHY_CLK]); 1208 - 1209 1184 return ret; 1210 1185 } 1211 1186 ··· 1210 1191 { 1211 1192 clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC1]); 1212 1193 clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]); 1213 - clk_disable_unprepare(sp->input_clks[PHY_CLK]); 1194 + if (!sp->already_configured) 1195 + clk_disable_unprepare(sp->input_clks[PHY_CLK]); 1214 1196 } 1215 1197 1216 1198 static int cdns_sierra_phy_get_resets(struct cdns_sierra_phy *sp, ··· 1402 1382 if (ret) 1403 1383 return ret; 1404 1384 1405 - ret = cdns_sierra_phy_get_resets(sp, dev); 1406 - if (ret) 1407 - goto unregister_clk; 1408 - 1409 1385 ret = cdns_sierra_phy_enable_clocks(sp); 1410 1386 if (ret) 1411 1387 goto unregister_clk; 1412 1388 1413 - /* Enable APB */ 1414 - reset_control_deassert(sp->apb_rst); 1389 + regmap_field_read(sp->pma_cmn_ready, &sp->already_configured); 1390 + 1391 + if (!sp->already_configured) { 1392 + ret = cdns_sierra_phy_clk(sp); 1393 + if (ret) 1394 + goto clk_disable; 1395 + 1396 + ret = cdns_sierra_phy_get_resets(sp, dev); 1397 + if (ret) 1398 + goto clk_disable; 1399 + 1400 + /* Enable APB */ 1401 + reset_control_deassert(sp->apb_rst); 1402 + } 1415 1403 1416 1404 /* Check that PHY is present */ 1417 1405 regmap_field_read(sp->macro_id_type, &id_value); 1418 1406 if (sp->init_data->id_value != id_value) { 1419 1407 ret = -EINVAL; 1420 - goto clk_disable; 1408 + goto ctrl_assert; 1421 1409 } 1422 1410 1423 1411 sp->autoconf = of_property_read_bool(dn, "cdns,autoconf"); ··· 1461 1433 1462 1434 sp->num_lanes += sp->phys[node].num_lanes; 1463 1435 1464 - gphy = devm_phy_create(dev, child, &ops); 1465 - 1436 + if (!sp->already_configured) 1437 + gphy = devm_phy_create(dev, child, &ops); 1438 + else 1439 + gphy = devm_phy_create(dev, child, &noop_ops); 1466 1440 if (IS_ERR(gphy)) { 1467 1441 ret = PTR_ERR(gphy); 1468 1442 of_node_put(child); ··· 1485 1455 } 1486 1456 1487 1457 /* If more than one subnode, configure the PHY as multilink */ 1488 - if (!sp->autoconf && sp->nsubnodes > 1) { 1458 + if (!sp->already_configured && !sp->autoconf && sp->nsubnodes > 1) { 1489 1459 ret = cdns_sierra_phy_configure_multilink(sp); 1490 1460 if (ret) 1491 1461 goto put_control; ··· 1503 1473 put_control: 1504 1474 while (--node >= 0) 1505 1475 reset_control_put(sp->phys[node].lnk_rst); 1476 + ctrl_assert: 1477 + if (!sp->already_configured) 1478 + reset_control_assert(sp->apb_rst); 1506 1479 clk_disable: 1507 1480 cdns_sierra_phy_disable_clocks(sp); 1508 - reset_control_assert(sp->apb_rst); 1509 1481 unregister_clk: 1510 1482 cdns_sierra_clk_unregister(sp); 1511 1483 return ret;