phy: cadence: Sierra: Add support for skipping configuration
authorAswath Govindraju <a-govindraju@ti.com>
Fri, 28 Jan 2022 08:11:50 +0000 (13:41 +0530)
committerTom Rini <trini@konsulko.com>
Tue, 8 Feb 2022 16:00:04 +0000 (11:00 -0500)
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>
drivers/phy/cadence/phy-cadence-sierra.c

index 95cdd39..d95d4b4 100644 (file)
@@ -13,6 +13,7 @@
  */
 #include <common.h>
 #include <clk.h>
+#include <linux/delay.h>
 #include <linux/clk-provider.h>
 #include <generic-phy.h>
 #include <reset.h>
@@ -28,6 +29,8 @@
 #include <dt-bindings/phy/phy-cadence.h>
 #include <regmap.h>
 
+#define usleep_range(a, b) udelay((b))
+
 #define NUM_SSC_MODE           3
 #define NUM_PHY_TYPE           4
 
@@ -336,6 +339,7 @@ struct cdns_sierra_phy {
        int nsubnodes;
        u32 num_lanes;
        bool autoconf;
+       unsigned int already_configured;
 };
 
 static inline int cdns_reset_assert(struct reset_control *rst)
@@ -386,7 +390,7 @@ static int cdns_sierra_phy_init(struct phy *gphy)
        int i, j;
 
        /* Initialise the PHY registers, unless auto configured */
-       if (phy->autoconf || phy->nsubnodes > 1)
+       if (phy->autoconf || phy->already_configured || phy->nsubnodes > 1)
                return 0;
 
        clk_set_rate(phy->input_clks[CMN_REFCLK_DIG_DIV], 25000000);
@@ -447,6 +451,11 @@ static int cdns_sierra_phy_on(struct phy *gphy)
        u32 val;
        int ret;
 
+       if (sp->already_configured) {
+               usleep_range(5000, 10000);
+               return 0;
+       }
+
        if (sp->nsubnodes == 1) {
                /* Take the PHY out of reset */
                ret = reset_control_deassert(sp->phy_rst);
@@ -934,13 +943,6 @@ static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp,
        struct clk *clk;
        int ret;
 
-       clk = devm_clk_get_optional(dev, "phy_clk");
-       if (IS_ERR(clk)) {
-               dev_err(dev, "failed to get clock phy_clk\n");
-               return PTR_ERR(clk);
-       }
-       sp->input_clks[PHY_CLK] = clk;
-
        clk = devm_clk_get_optional(dev, "cmn_refclk_dig_div");
        if (IS_ERR(clk)) {
                dev_err(dev, "cmn_refclk_dig_div clock not found\n");
@@ -976,6 +978,25 @@ static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp,
        return 0;
 }
 
+static int cdns_sierra_phy_clk(struct cdns_sierra_phy *sp)
+{
+       struct udevice *dev = sp->dev;
+       struct clk *clk;
+       int ret;
+
+       clk = devm_clk_get_optional(dev, "phy_clk");
+       if (IS_ERR(clk)) {
+               dev_err(dev, "failed to get clock phy_clk\n");
+               return PTR_ERR(clk);
+       }
+       sp->input_clks[PHY_CLK] = clk;
+
+       ret = clk_prepare_enable(sp->input_clks[PHY_CLK]);
+       if (ret)
+               return ret;
+
+       return 0;
+}
 static int cdns_sierra_phy_get_resets(struct cdns_sierra_phy *sp,
                                      struct udevice *dev)
 {
@@ -1045,7 +1066,7 @@ static int cdns_sierra_link_probe(struct udevice *dev)
        sp->num_lanes += inst->num_lanes;
 
        /* If more than one subnode, configure the PHY as multilink */
-       if (!sp->autoconf && sp->nsubnodes > 1) {
+       if (!sp->autoconf && !sp->already_configured && sp->nsubnodes > 1) {
                ret = cdns_sierra_phy_configure_multilink(sp);
                if (ret)
                        return ret;
@@ -1098,13 +1119,17 @@ static int cdns_sierra_phy_probe(struct udevice *dev)
        if (ret)
                return ret;
 
-       ret = cdns_sierra_phy_get_resets(sp, dev);
-       if (ret)
-               return ret;
+       regmap_field_read(sp->pma_cmn_ready, &sp->already_configured);
 
-       ret = clk_prepare_enable(sp->input_clks[PHY_CLK]);
-       if (ret)
-               return ret;
+       if (!sp->already_configured) {
+               ret = cdns_sierra_phy_clk(sp);
+               if (ret)
+                       return ret;
+
+               ret = cdns_sierra_phy_get_resets(sp, dev);
+               if (ret)
+                       return ret;
+       }
 
        /* Check that PHY is present */
        regmap_field_read(sp->macro_id_type, &id_value);
@@ -1125,7 +1150,8 @@ static int cdns_sierra_phy_probe(struct udevice *dev)
        return 0;
 
 clk_disable:
-       clk_disable_unprepare(sp->input_clks[PHY_CLK]);
+       if (!sp->already_configured)
+               clk_disable_unprepare(sp->input_clks[PHY_CLK]);
        return ret;
 }