linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] phy: ti: gmii-sel: update to support multiport k3 devices
@ 2020-08-28 20:19 Grygorii Strashko
  2020-08-28 20:19 ` [PATCH 1/3] phy: ti: gmii-sel: move phy init in separate function Grygorii Strashko
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Grygorii Strashko @ 2020-08-28 20:19 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Vinod Koul
  Cc: Vignesh Raghavendra, linux-kernel, Grygorii Strashko

Hi Kishon,

This series introduces support for multiport K3 CPSW devices like one, which
can be found on J721E SoC (MAIN CPSW).
The first two patches are preparation changes. The Patch 3 add support for
retrieving number of ports and base registers offset from DT.

Grygorii Strashko (3):
  phy: ti: gmii-sel: move phy init in separate function
  phy: ti: gmii-sel: use features mask during init
  phy: ti: gmii-sel: retrieve ports number and base offset from dt

 drivers/phy/ti/phy-gmii-sel.c | 159 ++++++++++++++++++++--------------
 1 file changed, 96 insertions(+), 63 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/3] phy: ti: gmii-sel: move phy init in separate function
  2020-08-28 20:19 [PATCH 0/3] phy: ti: gmii-sel: update to support multiport k3 devices Grygorii Strashko
@ 2020-08-28 20:19 ` Grygorii Strashko
  2020-08-28 20:19 ` [PATCH 2/3] phy: ti: gmii-sel: use features mask during init Grygorii Strashko
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Grygorii Strashko @ 2020-08-28 20:19 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Vinod Koul
  Cc: Vignesh Raghavendra, linux-kernel, Grygorii Strashko

Move phy initialization in separate function to improve code readability
and simplify future changes.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/phy/ti/phy-gmii-sel.c | 111 ++++++++++++++++++++--------------
 1 file changed, 64 insertions(+), 47 deletions(-)

diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c
index 7edd5c3bc536..d4b02ad023b2 100644
--- a/drivers/phy/ti/phy-gmii-sel.c
+++ b/drivers/phy/ti/phy-gmii-sel.c
@@ -22,7 +22,7 @@
 #define AM33XX_GMII_SEL_MODE_RGMII	2
 
 enum {
-	PHY_GMII_SEL_PORT_MODE,
+	PHY_GMII_SEL_PORT_MODE = 0,
 	PHY_GMII_SEL_RGMII_ID_MODE,
 	PHY_GMII_SEL_RMII_IO_CLK_EN,
 	PHY_GMII_SEL_LAST,
@@ -242,6 +242,66 @@ static struct phy *phy_gmii_sel_of_xlate(struct device *dev,
 	return priv->if_phys[phy_id].if_phy;
 }
 
+static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
+			     struct phy_gmii_sel_phy_priv *if_phy)
+{
+	const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data;
+	struct device *dev = priv->dev;
+	const struct reg_field *fields;
+	struct regmap_field *regfield;
+	struct reg_field field;
+	int ret;
+
+	if_phy->id = port;
+	if_phy->priv = priv;
+
+	fields = soc_data->regfields[port - 1];
+	field = *fields++;
+	dev_dbg(dev, "%s field %x %d %d\n", __func__,
+		field.reg, field.msb, field.lsb);
+
+	regfield = devm_regmap_field_alloc(dev, priv->regmap, field);
+	if (IS_ERR(regfield))
+		return PTR_ERR(regfield);
+	if_phy->fields[PHY_GMII_SEL_PORT_MODE] = regfield;
+
+	field = *fields++;
+	if (field.reg != (~0)) {
+		regfield = devm_regmap_field_alloc(dev,
+						   priv->regmap,
+						   field);
+		if (IS_ERR(regfield))
+			return PTR_ERR(regfield);
+		if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE] = regfield;
+		dev_dbg(dev, "%s field %x %d %d\n", __func__,
+			field.reg, field.msb, field.lsb);
+	}
+
+	field = *fields;
+	if (field.reg != (~0)) {
+		regfield = devm_regmap_field_alloc(dev,
+						   priv->regmap,
+						   field);
+		if (IS_ERR(regfield))
+			return PTR_ERR(regfield);
+		if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN] = regfield;
+		dev_dbg(dev, "%s field %x %d %d\n", __func__,
+			field.reg, field.msb, field.lsb);
+	}
+
+	if_phy->if_phy = devm_phy_create(dev,
+					 priv->dev->of_node,
+					 &phy_gmii_sel_ops);
+	if (IS_ERR(if_phy->if_phy)) {
+		ret = PTR_ERR(if_phy->if_phy);
+		dev_err(dev, "Failed to create phy%d %d\n", port, ret);
+		return ret;
+	}
+	phy_set_drvdata(if_phy->if_phy, if_phy);
+
+	return 0;
+}
+
 static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv *priv)
 {
 	const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data;
@@ -249,7 +309,7 @@ static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv *priv)
 	struct phy_gmii_sel_phy_priv *if_phys;
 	int i, num_ports, ret;
 
-	num_ports = priv->soc_data->num_ports;
+	num_ports = soc_data->num_ports;
 
 	if_phys = devm_kcalloc(priv->dev, num_ports,
 			       sizeof(*if_phys), GFP_KERNEL);
@@ -258,52 +318,9 @@ static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv *priv)
 	dev_dbg(dev, "%s %d\n", __func__, num_ports);
 
 	for (i = 0; i < num_ports; i++) {
-		const struct reg_field *field;
-		struct regmap_field *regfield;
-
-		if_phys[i].id = i + 1;
-		if_phys[i].priv = priv;
-
-		field = &soc_data->regfields[i][PHY_GMII_SEL_PORT_MODE];
-		dev_dbg(dev, "%s field %x %d %d\n", __func__,
-			field->reg, field->msb, field->lsb);
-
-		regfield = devm_regmap_field_alloc(dev, priv->regmap, *field);
-		if (IS_ERR(regfield))
-			return PTR_ERR(regfield);
-		if_phys[i].fields[PHY_GMII_SEL_PORT_MODE] = regfield;
-
-		field = &soc_data->regfields[i][PHY_GMII_SEL_RGMII_ID_MODE];
-		if (field->reg != (~0)) {
-			regfield = devm_regmap_field_alloc(dev,
-							   priv->regmap,
-							   *field);
-			if (IS_ERR(regfield))
-				return PTR_ERR(regfield);
-			if_phys[i].fields[PHY_GMII_SEL_RGMII_ID_MODE] =
-				regfield;
-		}
-
-		field = &soc_data->regfields[i][PHY_GMII_SEL_RMII_IO_CLK_EN];
-		if (field->reg != (~0)) {
-			regfield = devm_regmap_field_alloc(dev,
-							   priv->regmap,
-							   *field);
-			if (IS_ERR(regfield))
-				return PTR_ERR(regfield);
-			if_phys[i].fields[PHY_GMII_SEL_RMII_IO_CLK_EN] =
-				regfield;
-		}
-
-		if_phys[i].if_phy = devm_phy_create(dev,
-						    priv->dev->of_node,
-						    &phy_gmii_sel_ops);
-		if (IS_ERR(if_phys[i].if_phy)) {
-			ret = PTR_ERR(if_phys[i].if_phy);
-			dev_err(dev, "Failed to create phy%d %d\n", i, ret);
+		ret = phy_gmii_init_phy(priv, i + 1, &if_phys[i]);
+		if (ret)
 			return ret;
-		}
-		phy_set_drvdata(if_phys[i].if_phy, &if_phys[i]);
 	}
 
 	priv->if_phys = if_phys;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/3] phy: ti: gmii-sel: use features mask during init
  2020-08-28 20:19 [PATCH 0/3] phy: ti: gmii-sel: update to support multiport k3 devices Grygorii Strashko
  2020-08-28 20:19 ` [PATCH 1/3] phy: ti: gmii-sel: move phy init in separate function Grygorii Strashko
@ 2020-08-28 20:19 ` Grygorii Strashko
  2020-08-28 20:19 ` [PATCH 3/3] phy: ti: gmii-sel: retrieve ports number and base offset from dt Grygorii Strashko
  2020-09-08 10:25 ` [PATCH 0/3] phy: ti: gmii-sel: update to support multiport k3 devices Vinod Koul
  3 siblings, 0 replies; 6+ messages in thread
From: Grygorii Strashko @ 2020-08-28 20:19 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Vinod Koul
  Cc: Vignesh Raghavendra, linux-kernel, Grygorii Strashko

Use features mask during PHYs initialization to simplify code.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/phy/ti/phy-gmii-sel.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c
index d4b02ad023b2..a6b7f22e85c4 100644
--- a/drivers/phy/ti/phy-gmii-sel.c
+++ b/drivers/phy/ti/phy-gmii-sel.c
@@ -147,13 +147,9 @@ static const
 struct reg_field phy_gmii_sel_fields_dra7[][PHY_GMII_SEL_LAST] = {
 	{
 		[PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x554, 0, 1),
-		[PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD((~0), 0, 0),
-		[PHY_GMII_SEL_RMII_IO_CLK_EN] = REG_FIELD((~0), 0, 0),
 	},
 	{
 		[PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x554, 4, 5),
-		[PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD((~0), 0, 0),
-		[PHY_GMII_SEL_RMII_IO_CLK_EN] = REG_FIELD((~0), 0, 0),
 	},
 };
 
@@ -174,8 +170,6 @@ static const
 struct reg_field phy_gmii_sel_fields_am654[][PHY_GMII_SEL_LAST] = {
 	{
 		[PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4040, 0, 1),
-		[PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD((~0), 0, 0),
-		[PHY_GMII_SEL_RMII_IO_CLK_EN] = REG_FIELD((~0), 0, 0),
 	},
 };
 
@@ -266,7 +260,7 @@ static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
 	if_phy->fields[PHY_GMII_SEL_PORT_MODE] = regfield;
 
 	field = *fields++;
-	if (field.reg != (~0)) {
+	if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE)) {
 		regfield = devm_regmap_field_alloc(dev,
 						   priv->regmap,
 						   field);
@@ -278,7 +272,7 @@ static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
 	}
 
 	field = *fields;
-	if (field.reg != (~0)) {
+	if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN)) {
 		regfield = devm_regmap_field_alloc(dev,
 						   priv->regmap,
 						   field);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/3] phy: ti: gmii-sel: retrieve ports number and base offset from dt
  2020-08-28 20:19 [PATCH 0/3] phy: ti: gmii-sel: update to support multiport k3 devices Grygorii Strashko
  2020-08-28 20:19 ` [PATCH 1/3] phy: ti: gmii-sel: move phy init in separate function Grygorii Strashko
  2020-08-28 20:19 ` [PATCH 2/3] phy: ti: gmii-sel: use features mask during init Grygorii Strashko
@ 2020-08-28 20:19 ` Grygorii Strashko
  2020-09-08 10:25 ` [PATCH 0/3] phy: ti: gmii-sel: update to support multiport k3 devices Vinod Koul
  3 siblings, 0 replies; 6+ messages in thread
From: Grygorii Strashko @ 2020-08-28 20:19 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Vinod Koul
  Cc: Vignesh Raghavendra, linux-kernel, Grygorii Strashko

On K3 AM654x/J721E platforms the Port MII mode selection register(s) have
similar format and placed in the System Control Module (SCM) module
sequentially as one register per port, but, depending SOC and CPSW
instance, the base offset and number of ports can be different.

Hence, add possibility to retrieve number of ports and base registers
offset from DT and support for max possible number of ports supported by K3
SoCs like J721E.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/phy/ti/phy-gmii-sel.c | 44 ++++++++++++++++++++++++++---------
 1 file changed, 33 insertions(+), 11 deletions(-)

diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c
index a6b7f22e85c4..5fd2e8a08bfc 100644
--- a/drivers/phy/ti/phy-gmii-sel.c
+++ b/drivers/phy/ti/phy-gmii-sel.c
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/mfd/syscon.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/of_net.h>
 #include <linux/phy.h>
 #include <linux/phy/phy.h>
@@ -41,6 +42,7 @@ struct phy_gmii_sel_soc_data {
 	u32 num_ports;
 	u32 features;
 	const struct reg_field (*regfields)[PHY_GMII_SEL_LAST];
+	bool use_of_data;
 };
 
 struct phy_gmii_sel_priv {
@@ -49,6 +51,8 @@ struct phy_gmii_sel_priv {
 	struct regmap *regmap;
 	struct phy_provider *phy_provider;
 	struct phy_gmii_sel_phy_priv *if_phys;
+	u32 num_ports;
+	u32 reg_offset;
 };
 
 static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode)
@@ -168,14 +172,19 @@ struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dm814 = {
 
 static const
 struct reg_field phy_gmii_sel_fields_am654[][PHY_GMII_SEL_LAST] = {
-	{
-		[PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4040, 0, 1),
-	},
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x0, 0, 2), },
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4, 0, 2), },
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x8, 0, 2), },
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0xC, 0, 2), },
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x10, 0, 2), },
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x14, 0, 2), },
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x18, 0, 2), },
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x1C, 0, 2), },
 };
 
 static const
 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = {
-	.num_ports = 1,
+	.use_of_data = true,
 	.regfields = phy_gmii_sel_fields_am654,
 };
 
@@ -222,7 +231,7 @@ static struct phy *phy_gmii_sel_of_xlate(struct device *dev,
 	if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) &&
 	    args->args_count < 2)
 		return ERR_PTR(-EINVAL);
-	if (phy_id > priv->soc_data->num_ports)
+	if (phy_id > priv->num_ports)
 		return ERR_PTR(-EINVAL);
 	if (phy_id != priv->if_phys[phy_id - 1].id)
 		return ERR_PTR(-EINVAL);
@@ -251,6 +260,7 @@ static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
 
 	fields = soc_data->regfields[port - 1];
 	field = *fields++;
+	field.reg += priv->reg_offset;
 	dev_dbg(dev, "%s field %x %d %d\n", __func__,
 		field.reg, field.msb, field.lsb);
 
@@ -260,6 +270,7 @@ static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
 	if_phy->fields[PHY_GMII_SEL_PORT_MODE] = regfield;
 
 	field = *fields++;
+	field.reg += priv->reg_offset;
 	if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE)) {
 		regfield = devm_regmap_field_alloc(dev,
 						   priv->regmap,
@@ -272,6 +283,7 @@ static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
 	}
 
 	field = *fields;
+	field.reg += priv->reg_offset;
 	if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN)) {
 		regfield = devm_regmap_field_alloc(dev,
 						   priv->regmap,
@@ -299,19 +311,28 @@ static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
 static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv *priv)
 {
 	const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data;
-	struct device *dev = priv->dev;
 	struct phy_gmii_sel_phy_priv *if_phys;
-	int i, num_ports, ret;
+	struct device *dev = priv->dev;
+	int i, ret;
+
+	if (soc_data->use_of_data) {
+		const __be32 *offset;
+		u64 size;
 
-	num_ports = soc_data->num_ports;
+		offset = of_get_address(dev->of_node, 0, &size, NULL);
+		priv->num_ports = size / sizeof(u32);
+		if (!priv->num_ports)
+			return -EINVAL;
+		priv->reg_offset = __be32_to_cpu(*offset);
+	}
 
-	if_phys = devm_kcalloc(priv->dev, num_ports,
+	if_phys = devm_kcalloc(dev, priv->num_ports,
 			       sizeof(*if_phys), GFP_KERNEL);
 	if (!if_phys)
 		return -ENOMEM;
-	dev_dbg(dev, "%s %d\n", __func__, num_ports);
+	dev_dbg(dev, "%s %d\n", __func__, priv->num_ports);
 
-	for (i = 0; i < num_ports; i++) {
+	for (i = 0; i < priv->num_ports; i++) {
 		ret = phy_gmii_init_phy(priv, i + 1, &if_phys[i]);
 		if (ret)
 			return ret;
@@ -339,6 +360,7 @@ static int phy_gmii_sel_probe(struct platform_device *pdev)
 
 	priv->dev = &pdev->dev;
 	priv->soc_data = of_id->data;
+	priv->num_ports = priv->soc_data->num_ports;
 
 	priv->regmap = syscon_node_to_regmap(node->parent);
 	if (IS_ERR(priv->regmap)) {
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 0/3] phy: ti: gmii-sel: update to support multiport k3 devices
  2020-08-28 20:19 [PATCH 0/3] phy: ti: gmii-sel: update to support multiport k3 devices Grygorii Strashko
                   ` (2 preceding siblings ...)
  2020-08-28 20:19 ` [PATCH 3/3] phy: ti: gmii-sel: retrieve ports number and base offset from dt Grygorii Strashko
@ 2020-09-08 10:25 ` Vinod Koul
  3 siblings, 0 replies; 6+ messages in thread
From: Vinod Koul @ 2020-09-08 10:25 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Kishon Vijay Abraham I, Vignesh Raghavendra, linux-kernel

On 28-08-20, 23:19, Grygorii Strashko wrote:
> Hi Kishon,
> 
> This series introduces support for multiport K3 CPSW devices like one, which
> can be found on J721E SoC (MAIN CPSW).
> The first two patches are preparation changes. The Patch 3 add support for
> retrieving number of ports and base registers offset from DT.

Applied all, thanks

-- 
~Vinod

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 3/3] phy: ti: gmii-sel: retrieve ports number and base offset from dt
  2020-07-21 23:29 Grygorii Strashko
@ 2020-07-21 23:29 ` Grygorii Strashko
  0 siblings, 0 replies; 6+ messages in thread
From: Grygorii Strashko @ 2020-07-21 23:29 UTC (permalink / raw)
  To: Kishon Vijay Abraham I; +Cc: Sekhar Nori, linux-kernel, Grygorii Strashko

On K3 AM654x/J721E platforms the Port MII mode selection register(s) have
similar format and placed in the System Control Module (SCM) module
sequentially as one register per port, but, depending SOC and CPSW
instance, the base offset and number of ports can be different.

Hence, add possibility to retrieve number of ports and base registers
offset from DT and support for max possible number of ports supported by K3
SoCs like J721E.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/phy/ti/phy-gmii-sel.c | 44 ++++++++++++++++++++++++++---------
 1 file changed, 33 insertions(+), 11 deletions(-)

diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c
index a6b7f22e85c4..5fd2e8a08bfc 100644
--- a/drivers/phy/ti/phy-gmii-sel.c
+++ b/drivers/phy/ti/phy-gmii-sel.c
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/mfd/syscon.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/of_net.h>
 #include <linux/phy.h>
 #include <linux/phy/phy.h>
@@ -41,6 +42,7 @@ struct phy_gmii_sel_soc_data {
 	u32 num_ports;
 	u32 features;
 	const struct reg_field (*regfields)[PHY_GMII_SEL_LAST];
+	bool use_of_data;
 };
 
 struct phy_gmii_sel_priv {
@@ -49,6 +51,8 @@ struct phy_gmii_sel_priv {
 	struct regmap *regmap;
 	struct phy_provider *phy_provider;
 	struct phy_gmii_sel_phy_priv *if_phys;
+	u32 num_ports;
+	u32 reg_offset;
 };
 
 static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode)
@@ -168,14 +172,19 @@ struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dm814 = {
 
 static const
 struct reg_field phy_gmii_sel_fields_am654[][PHY_GMII_SEL_LAST] = {
-	{
-		[PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4040, 0, 1),
-	},
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x0, 0, 2), },
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4, 0, 2), },
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x8, 0, 2), },
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0xC, 0, 2), },
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x10, 0, 2), },
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x14, 0, 2), },
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x18, 0, 2), },
+	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x1C, 0, 2), },
 };
 
 static const
 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = {
-	.num_ports = 1,
+	.use_of_data = true,
 	.regfields = phy_gmii_sel_fields_am654,
 };
 
@@ -222,7 +231,7 @@ static struct phy *phy_gmii_sel_of_xlate(struct device *dev,
 	if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) &&
 	    args->args_count < 2)
 		return ERR_PTR(-EINVAL);
-	if (phy_id > priv->soc_data->num_ports)
+	if (phy_id > priv->num_ports)
 		return ERR_PTR(-EINVAL);
 	if (phy_id != priv->if_phys[phy_id - 1].id)
 		return ERR_PTR(-EINVAL);
@@ -251,6 +260,7 @@ static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
 
 	fields = soc_data->regfields[port - 1];
 	field = *fields++;
+	field.reg += priv->reg_offset;
 	dev_dbg(dev, "%s field %x %d %d\n", __func__,
 		field.reg, field.msb, field.lsb);
 
@@ -260,6 +270,7 @@ static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
 	if_phy->fields[PHY_GMII_SEL_PORT_MODE] = regfield;
 
 	field = *fields++;
+	field.reg += priv->reg_offset;
 	if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE)) {
 		regfield = devm_regmap_field_alloc(dev,
 						   priv->regmap,
@@ -272,6 +283,7 @@ static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
 	}
 
 	field = *fields;
+	field.reg += priv->reg_offset;
 	if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN)) {
 		regfield = devm_regmap_field_alloc(dev,
 						   priv->regmap,
@@ -299,19 +311,28 @@ static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
 static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv *priv)
 {
 	const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data;
-	struct device *dev = priv->dev;
 	struct phy_gmii_sel_phy_priv *if_phys;
-	int i, num_ports, ret;
+	struct device *dev = priv->dev;
+	int i, ret;
+
+	if (soc_data->use_of_data) {
+		const __be32 *offset;
+		u64 size;
 
-	num_ports = soc_data->num_ports;
+		offset = of_get_address(dev->of_node, 0, &size, NULL);
+		priv->num_ports = size / sizeof(u32);
+		if (!priv->num_ports)
+			return -EINVAL;
+		priv->reg_offset = __be32_to_cpu(*offset);
+	}
 
-	if_phys = devm_kcalloc(priv->dev, num_ports,
+	if_phys = devm_kcalloc(dev, priv->num_ports,
 			       sizeof(*if_phys), GFP_KERNEL);
 	if (!if_phys)
 		return -ENOMEM;
-	dev_dbg(dev, "%s %d\n", __func__, num_ports);
+	dev_dbg(dev, "%s %d\n", __func__, priv->num_ports);
 
-	for (i = 0; i < num_ports; i++) {
+	for (i = 0; i < priv->num_ports; i++) {
 		ret = phy_gmii_init_phy(priv, i + 1, &if_phys[i]);
 		if (ret)
 			return ret;
@@ -339,6 +360,7 @@ static int phy_gmii_sel_probe(struct platform_device *pdev)
 
 	priv->dev = &pdev->dev;
 	priv->soc_data = of_id->data;
+	priv->num_ports = priv->soc_data->num_ports;
 
 	priv->regmap = syscon_node_to_regmap(node->parent);
 	if (IS_ERR(priv->regmap)) {
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-09-08 10:25 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-28 20:19 [PATCH 0/3] phy: ti: gmii-sel: update to support multiport k3 devices Grygorii Strashko
2020-08-28 20:19 ` [PATCH 1/3] phy: ti: gmii-sel: move phy init in separate function Grygorii Strashko
2020-08-28 20:19 ` [PATCH 2/3] phy: ti: gmii-sel: use features mask during init Grygorii Strashko
2020-08-28 20:19 ` [PATCH 3/3] phy: ti: gmii-sel: retrieve ports number and base offset from dt Grygorii Strashko
2020-09-08 10:25 ` [PATCH 0/3] phy: ti: gmii-sel: update to support multiport k3 devices Vinod Koul
  -- strict thread matches above, loose matches on Subject: below --
2020-07-21 23:29 Grygorii Strashko
2020-07-21 23:29 ` [PATCH 3/3] phy: ti: gmii-sel: retrieve ports number and base offset from dt Grygorii Strashko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).