Re: [PATCH v3 2/2] phy: ti: gmii-sel: Add support for CPSW5G GMII SEL in J7200

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Siddharth,

On 29/08/2022 07:53, Siddharth Vadapalli wrote:
> Hello Roger,
> 
> On 25/08/22 13:11, Roger Quadros wrote:
>> Hi Siddharth,
>>
>> On 22/08/2022 09:56, Siddharth Vadapalli wrote:
>>> Each of the CPSW5G ports in J7200 support additional modes like QSGMII.
>>> Add a new compatible for J7200 to support the additional modes.
>>>
>>> In TI's J7200, each of the CPSW5G ethernet interfaces can act as a
>>> QSGMII or QSGMII-SUB port. The QSGMII interface is responsible for
>>> performing auto-negotiation between the MAC and the PHY while the rest of
>>> the interfaces are designated as QSGMII-SUB interfaces, indicating that
>>> they will not be taking part in the auto-negotiation process.
>>>
>>> To indicate the interface which will serve as the main QSGMII interface,
>>> add a property "ti,qsgmii-main-ports", whose value indicates the
>>> port number of the interface which shall serve as the main QSGMII
>>> interface. The rest of the interfaces are then assigned QSGMII-SUB mode by
>>> default.
>>
>> Can you please describe here why you are using "ti,qsgmii-main-ports" instead
>> of "ti,qsgmii-main-port" as there can be only one main port per PHY instance?
> 
> Thank you for reviewing the patch. I am using "ports" instead of "port"
> because I plan to add support for CPSW9G on TI's J721e device in the
> future patches. CPSW9G (8 external ports) supports up to two QSGMII main
> ports. For CPSW9G, by specifying the two main ports in the device tree,
> it is possible to configure the CTRLMMR_ENETx_CTRL register for each of
> the 8 ports, with the two QSGMII main ports being configured as main
> ports in the CTRLMMR_ENETx_CTRL register and the rest of them being
> configured as sub ports. Since I will be using the same property
> "ti,qsgmii-main-ports" for CPSW9G as well, the property will be an array
> of 2 values for CPSW9G. Therefore, I am using "ports" instead of "port".
> Please let me know if this is fine.
> 

OK. Please mention this in commit message.

>>
>>>
>>> Signed-off-by: Siddharth Vadapalli <s-vadapalli@xxxxxx>
>>> ---
>>>  drivers/phy/ti/phy-gmii-sel.c | 40 ++++++++++++++++++++++++++++++++---
>>>  1 file changed, 37 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c
>>> index d0ab69750c6b..270083606b14 100644
>>> --- a/drivers/phy/ti/phy-gmii-sel.c
>>> +++ b/drivers/phy/ti/phy-gmii-sel.c
>>> @@ -22,6 +22,12 @@
>>>  #define AM33XX_GMII_SEL_MODE_RMII	1
>>>  #define AM33XX_GMII_SEL_MODE_RGMII	2
>>>  
>>> +/* J72xx SoC specific definitions for the CONTROL port */
>>> +#define J72XX_GMII_SEL_MODE_QSGMII	4
>>> +#define J72XX_GMII_SEL_MODE_QSGMII_SUB	6
>>> +
>>> +#define PHY_GMII_PORT(n)	BIT((n) - 1)
>>> +
>>>  enum {
>>>  	PHY_GMII_SEL_PORT_MODE = 0,
>>>  	PHY_GMII_SEL_RGMII_ID_MODE,
>>> @@ -43,6 +49,7 @@ struct phy_gmii_sel_soc_data {
>>>  	u32 features;
>>>  	const struct reg_field (*regfields)[PHY_GMII_SEL_LAST];
>>>  	bool use_of_data;
>>> +	u64 extra_modes;
>>>  };
>>>  
>>>  struct phy_gmii_sel_priv {
>>> @@ -53,6 +60,7 @@ struct phy_gmii_sel_priv {
>>>  	struct phy_gmii_sel_phy_priv *if_phys;
>>>  	u32 num_ports;
>>>  	u32 reg_offset;
>>> +	u32 qsgmii_main_ports;
>>>  };
>>>  
>>>  static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode)
>>> @@ -88,10 +96,17 @@ static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode)
>>>  		gmii_sel_mode = AM33XX_GMII_SEL_MODE_MII;
>>>  		break;
>>>  
>>> +	case PHY_INTERFACE_MODE_QSGMII:
>>> +		if (!(soc_data->extra_modes & BIT(PHY_INTERFACE_MODE_QSGMII)))
>>> +			goto unsupported;
>>> +		if (if_phy->priv->qsgmii_main_ports & BIT(if_phy->id - 1))
>>> +			gmii_sel_mode = J72XX_GMII_SEL_MODE_QSGMII;
>>> +		else
>>> +			gmii_sel_mode = J72XX_GMII_SEL_MODE_QSGMII_SUB;
>>> +		break;
>>> +
>>>  	default:
>>> -		dev_warn(dev, "port%u: unsupported mode: \"%s\"\n",
>>> -			 if_phy->id, phy_modes(submode));
>>> -		return -EINVAL;
>>> +		goto unsupported;
>>>  	}
>>>  
>>>  	if_phy->phy_if_mode = submode;
>>> @@ -123,6 +138,11 @@ static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode)
>>>  	}
>>>  
>>>  	return 0;
>>> +
>>> +unsupported:
>>> +	dev_warn(dev, "port%u: unsupported mode: \"%s\"\n",
>>> +		 if_phy->id, phy_modes(submode));
>>> +	return -EINVAL;
>>>  }
>>>  
>>>  static const
>>> @@ -188,6 +208,13 @@ struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = {
>>>  	.regfields = phy_gmii_sel_fields_am654,
>>>  };
>>>  
>>> +static const
>>> +struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw5g_soc_j7200 = {
>>> +	.use_of_data = true,
>>> +	.regfields = phy_gmii_sel_fields_am654,
>>> +	.extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII),
>>> +};
>>> +
>>>  static const struct of_device_id phy_gmii_sel_id_table[] = {
>>>  	{
>>>  		.compatible	= "ti,am3352-phy-gmii-sel",
>>> @@ -209,6 +236,10 @@ static const struct of_device_id phy_gmii_sel_id_table[] = {
>>>  		.compatible	= "ti,am654-phy-gmii-sel",
>>>  		.data		= &phy_gmii_sel_soc_am654,
>>>  	},
>>> +	{
>>> +		.compatible	= "ti,j7200-cpsw5g-phy-gmii-sel",
>>> +		.data		= &phy_gmii_sel_cpsw5g_soc_j7200,
>>> +	},
>>>  	{}
>>>  };
>>>  MODULE_DEVICE_TABLE(of, phy_gmii_sel_id_table);
>>> @@ -350,6 +381,7 @@ static int phy_gmii_sel_probe(struct platform_device *pdev)
>>>  	struct device_node *node = dev->of_node;
>>>  	const struct of_device_id *of_id;
>>>  	struct phy_gmii_sel_priv *priv;
>>> +	u32 main_ports = 1;
>>>  	int ret;
>>>  
>>>  	of_id = of_match_node(phy_gmii_sel_id_table, pdev->dev.of_node);
>>> @@ -363,6 +395,8 @@ 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;
>>> +	of_property_read_u32_array(node, "ti,qsgmii-main-ports", &main_ports, 1);
>>
>> of_property_read_u32_array can return error and you are not doing any sanity checks.
>> This should fail if "ti,qsgmii-main-ports" is not present or out of bounds if port mode is QSGMII.
> 
> In the scenario that the user doesn't want to use QSGMII mode, the
> property will not be mentioned in the device tree. In the phy-gmii-sel
> driver, the call to of_property_read_u32_array() will return an error
> since the optional ti,qsgmii-main-ports property doesn't exist in the
> device tree. However, the main_ports variable has already been
> initialized to 1 and in case of Non-QSGMII modes, the main_ports
> variable will not even be used. If the mode is QSGMII and the user
> forgets to mention the ti,qsgmii-main-ports property in the device tree,
> then the default value of 1 is used.
> 
> Since the of_property_read_u32_array() function doesn't overwrite
> main_ports variable if the ti,qsgmii-main-ports property is not present
> in the device tree, the value of main_ports will continue to remain 1
> even in the case where of_property_read_u32_array() errors out.
> 
> In the other scenario where the user mentions a value that is smaller or
> greater than the allowed value for "ti,qsgmii-main-ports" property, I
> have added bindings to ensure that make dtbs_check fails. This will
> enforce the bounds on the property.

This I'm not sure about. dtbs_check is not always run at build time and we cannot
depend on that.

> 
> For the above reasons, I think that the return value of the call to
> of_property_read_u32_array() can be safely ignored, and the value of
> main_ports doesn't need to be validated within the driver as it is being
> enforced in the bindings.
> 
>>
>> How is this going to scale if you are going to have multiple main ports?
>> Let's say you increase it to 2 in the future. won't this break with -EOVERFLOW for older
>> DTs where you had only 1 u32.
> 
> For multiple main ports (like CPSW9G for example), I had planned to add
> an IF-ELSE condition to check the compatible (I plan to add a new
> compatible for J721e which uses CPSW9G) and then call
> of_property_read_u32_array() with either 1 or 2 values to be read based
> on the compatible.

In that case please use of_property_read_u32 for the case where you know only there is only 1 value.

> 
> Please let me know if you have a suggestion for a better way to
> implement this.
> 
> Regards,
> Siddharth.

cheers,
-roger



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux