summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAswath Govindraju <a-govindraju@ti.com>2022-01-28 11:11:35 +0300
committerTom Rini <trini@konsulko.com>2022-02-08 19:00:03 +0300
commit6f46c7441a9f02133ae997238712819dab8c95ee (patch)
treeda5ab2078f901729ceea3510d844adefecd75d01
parente7a2986ec761719370674e9c96262ce6beaf56fe (diff)
downloadu-boot-6f46c7441a9f02133ae997238712819dab8c95ee.tar.xz
phy: cadence: Sierra: Add a UCLASS_PHY device for links
Add a driver of type UCLASS_PHY for each of the link nodes in the serdes instance. Signed-off-by: Aswath Govindraju <a-govindraju@ti.com>
-rw-r--r--drivers/phy/cadence/phy-cadence-sierra.c116
1 files changed, 75 insertions, 41 deletions
diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c
index 90699f2fa6..af67df6d06 100644
--- a/drivers/phy/cadence/phy-cadence-sierra.c
+++ b/drivers/phy/cadence/phy-cadence-sierra.c
@@ -203,7 +203,7 @@ struct cdns_sierra_phy {
size_t size;
struct regmap *regmap;
struct cdns_sierra_data *init_data;
- struct cdns_sierra_inst phys[SIERRA_MAX_LANES];
+ struct cdns_sierra_inst *phys[SIERRA_MAX_LANES];
struct reset_control *phy_rst;
struct regmap *regmap_lane_cdb[SIERRA_MAX_LANES];
struct regmap *regmap_phy_config_ctrl;
@@ -242,8 +242,8 @@ static inline struct cdns_sierra_inst *phy_get_drvdata(struct phy *phy)
return NULL;
for (index = 0; index < sp->nsubnodes; index++) {
- if (phy->id == sp->phys[index].mlane)
- return &sp->phys[index];
+ if (phy->id == sp->phys[index]->mlane)
+ return sp->phys[index];
}
return NULL;
@@ -500,13 +500,79 @@ static int cdns_sierra_phy_get_resets(struct cdns_sierra_phy *sp,
return 0;
}
+static int cdns_sierra_bind_link_nodes(struct cdns_sierra_phy *sp)
+{
+ struct udevice *dev = sp->dev;
+ struct driver *link_drv;
+ ofnode child;
+ int rc;
+
+ link_drv = lists_driver_lookup_name("sierra_phy_link");
+ if (!link_drv) {
+ dev_err(dev, "Cannot find driver 'sierra_phy_link'\n");
+ return -ENOENT;
+ }
+
+ ofnode_for_each_subnode(child, dev_ofnode(dev)) {
+ if (!(ofnode_name_eq(child, "phy") ||
+ ofnode_name_eq(child, "link")))
+ continue;
+
+ rc = device_bind(dev, link_drv, "link", NULL, child, NULL);
+ if (rc) {
+ dev_err(dev, "cannot bind driver for link\n");
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static int cdns_sierra_link_probe(struct udevice *dev)
+{
+ struct cdns_sierra_inst *inst = dev_get_priv(dev);
+ struct cdns_sierra_phy *sp = dev_get_priv(dev->parent);
+ struct reset_ctl_bulk *rst;
+ int ret, node;
+
+ rst = devm_reset_bulk_get_by_node(dev, dev_ofnode(dev));
+ if (IS_ERR(rst)) {
+ ret = PTR_ERR(rst);
+ dev_err(dev, "failed to get reset\n");
+ return ret;
+ }
+ inst->lnk_rst = rst;
+
+ ret = cdns_sierra_get_optional(inst, dev_ofnode(dev));
+ if (ret) {
+ dev_err(dev, "missing property in node\n");
+ return ret;
+ }
+ node = sp->nsubnodes;
+ sp->phys[node] = inst;
+ sp->nsubnodes += 1;
+ sp->num_lanes += inst->num_lanes;
+
+ /* If more than one subnode, configure the PHY as multilink */
+ if (!sp->autoconf && sp->nsubnodes > 1)
+ regmap_field_write(sp->phy_pll_cfg_1, 0x1);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(sierra_phy_link) = {
+ .name = "sierra_phy_link",
+ .id = UCLASS_PHY,
+ .probe = cdns_sierra_link_probe,
+ .priv_auto = sizeof(struct cdns_sierra_inst),
+};
+
static int cdns_sierra_phy_probe(struct udevice *dev)
{
struct cdns_sierra_phy *sp = dev_get_priv(dev);
struct cdns_sierra_data *data;
unsigned int id_value;
int ret, node = 0;
- ofnode child;
sp->dev = dev;
@@ -558,46 +624,14 @@ static int cdns_sierra_phy_probe(struct udevice *dev)
}
sp->autoconf = dev_read_bool(dev, "cdns,autoconf");
-
- ofnode_for_each_subnode(child, dev_ofnode(dev)) {
- if (!(ofnode_name_eq(child, "phy") ||
- ofnode_name_eq(child, "link")))
- continue;
-
- sp->phys[node].lnk_rst = devm_reset_bulk_get_by_node(dev,
- child);
- if (IS_ERR(sp->phys[node].lnk_rst)) {
- ret = PTR_ERR(sp->phys[node].lnk_rst);
- dev_err(dev, "failed to get reset %s\n",
- ofnode_get_name(child));
- goto put_child2;
- }
-
- if (!sp->autoconf) {
- ret = cdns_sierra_get_optional(&sp->phys[node], child);
- if (ret) {
- dev_err(dev, "missing property in node %s\n",
- ofnode_get_name(child));
- goto put_child;
- }
- }
- sp->num_lanes += sp->phys[node].num_lanes;
-
- node++;
- }
- sp->nsubnodes = node;
-
- /* If more than one subnode, configure the PHY as multilink */
- if (!sp->autoconf && sp->nsubnodes > 1)
- regmap_field_write(sp->phy_pll_cfg_1, 0x1);
+ /* Binding link nodes as children to serdes */
+ ret = cdns_sierra_bind_link_nodes(sp);
+ if (ret)
+ goto clk_disable;
dev_info(dev, "sierra probed\n");
return 0;
-put_child:
- node++;
-put_child2:
-
clk_disable:
clk_disable_unprepare(sp->input_clks[PHY_CLK]);
return ret;
@@ -615,7 +649,7 @@ static int cdns_sierra_phy_remove(struct udevice *dev)
* Need to put the subnode resets here though.
*/
for (i = 0; i < phy->nsubnodes; i++)
- reset_assert_bulk(phy->phys[i].lnk_rst);
+ reset_assert_bulk(phy->phys[i]->lnk_rst);
clk_disable_unprepare(phy->input_clks[PHY_CLK]);