@@ -364,6 +364,10 @@ static const struct phy_ops ops = {
.owner = THIS_MODULE,
};
+static const struct phy_ops noop_ops = {
+ .owner = THIS_MODULE,
+};
+
static int cdns_sierra_get_optional(struct cdns_sierra_inst *inst,
struct device_node *child)
{
@@ -477,6 +481,49 @@ static int cdns_regmap_init_blocks(struct cdns_sierra_phy *sp,
return 0;
}
+static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp,
+ struct device *dev)
+{
+ struct clk *clk;
+ int ret;
+
+ sp->clk = devm_clk_get_optional(dev, "phy_clk");
+ if (IS_ERR(sp->clk)) {
+ dev_err(dev, "failed to get clock phy_clk\n");
+ return PTR_ERR(sp->clk);
+ }
+
+ sp->phy_rst = devm_reset_control_get(dev, "sierra_reset");
+ if (IS_ERR(sp->phy_rst)) {
+ dev_err(dev, "failed to get reset\n");
+ return PTR_ERR(sp->phy_rst);
+ }
+
+ sp->apb_rst = devm_reset_control_get_optional(dev, "sierra_apb");
+ if (IS_ERR(sp->apb_rst)) {
+ dev_err(dev, "failed to get apb reset\n");
+ return PTR_ERR(sp->apb_rst);
+ }
+
+ 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");
+ ret = PTR_ERR(clk);
+ return ret;
+ }
+ sp->cmn_refclk_dig_div = clk;
+
+ clk = devm_clk_get_optional(dev, "cmn_refclk1_dig_div");
+ if (IS_ERR(clk)) {
+ dev_err(dev, "cmn_refclk1_dig_div clock not found\n");
+ ret = PTR_ERR(clk);
+ return ret;
+ }
+ sp->cmn_refclk1_dig_div = clk;
+
+ return 0;
+}
+
static int cdns_sierra_phy_probe(struct platform_device *pdev)
{
struct cdns_sierra_phy *sp;
@@ -486,10 +533,10 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
struct cdns_sierra_data *data;
unsigned int id_value;
struct resource *res;
- int i, ret, node = 0;
+ int i, val, ret, node = 0;
void __iomem *base;
- struct clk *clk;
struct device_node *dn = dev->of_node, *child;
+ bool already_configured = false;
if (of_get_child_count(dn) == 0)
return -ENODEV;
@@ -524,54 +571,33 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
if (ret)
return ret;
- platform_set_drvdata(pdev, sp);
-
- sp->clk = devm_clk_get_optional(dev, "phy_clk");
- if (IS_ERR(sp->clk)) {
- dev_err(dev, "failed to get clock phy_clk\n");
- return PTR_ERR(sp->clk);
- }
-
- sp->phy_rst = devm_reset_control_get(dev, "sierra_reset");
- if (IS_ERR(sp->phy_rst)) {
- dev_err(dev, "failed to get reset\n");
- return PTR_ERR(sp->phy_rst);
- }
-
- sp->apb_rst = devm_reset_control_get_optional(dev, "sierra_apb");
- if (IS_ERR(sp->apb_rst)) {
- dev_err(dev, "failed to get apb reset\n");
- return PTR_ERR(sp->apb_rst);
- }
-
- 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");
- ret = PTR_ERR(clk);
- return ret;
- }
- sp->cmn_refclk_dig_div = clk;
-
- clk = devm_clk_get_optional(dev, "cmn_refclk1_dig_div");
- if (IS_ERR(clk)) {
- dev_err(dev, "cmn_refclk1_dig_div clock not found\n");
- ret = PTR_ERR(clk);
- return ret;
+ for (i = 0; i < SIERRA_MAX_LANES; i++) {
+ regmap_field_read(sp->pllctrl_lock[i], &val);
+ if (val) {
+ already_configured = true;
+ break;
+ }
}
- sp->cmn_refclk1_dig_div = clk;
- ret = clk_prepare_enable(sp->clk);
- if (ret)
- return ret;
-
- /* Enable APB */
- reset_control_deassert(sp->apb_rst);
+ platform_set_drvdata(pdev, sp);
- /* Check that PHY is present */
- regmap_field_read(sp->macro_id_type, &id_value);
- if (sp->init_data->id_value != id_value) {
- ret = -EINVAL;
- goto clk_disable;
+ if (!already_configured) {
+ ret = cdns_sierra_phy_get_clocks(sp, dev);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(sp->clk);
+ if (ret)
+ return ret;
+ /* Enable APB */
+ reset_control_deassert(sp->apb_rst);
+
+ /* Check that PHY is present */
+ regmap_field_read(sp->macro_id_type, &id_value);
+ if (sp->init_data->id_value != id_value) {
+ ret = -EINVAL;
+ goto clk_disable;
+ }
}
sp->autoconf = of_property_read_bool(dn, "cdns,autoconf");
@@ -603,7 +629,10 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
sp->num_lanes += sp->phys[node].num_lanes;
- gphy = devm_phy_create(dev, child, &ops);
+ if (already_configured)
+ gphy = devm_phy_create(dev, child, &noop_ops);
+ else
+ gphy = devm_phy_create(dev, child, &ops);
if (IS_ERR(gphy)) {
ret = PTR_ERR(gphy);
@@ -622,7 +651,7 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
}
/* If more than one subnode, configure the PHY as multilink */
- if (!sp->autoconf && sp->nsubnodes > 1)
+ if (!sp->autoconf && sp->nsubnodes > 1 && !already_configured)
regmap_field_write(sp->phy_pll_cfg_1, 0x1);
pm_runtime_enable(dev);