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>
This commit is contained in:
Aswath Govindraju 2022-01-28 13:41:50 +05:30 committed by Tom Rini
parent fa294b274b
commit 68c6476146

View 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;
}