diff mbox

[v3,1/6] phy: add a driver for the Berlin SATA PHY

Message ID 1400060942-10588-2-git-send-email-antoine.tenart@free-electrons.com (mailing list archive)
State New, archived
Headers show

Commit Message

Antoine Tenart May 14, 2014, 9:48 a.m. UTC
The Berlin SoC has a two SATA ports. Add a PHY driver to handle them.

Signed-off-by: Antoine Ténart <antoine.tenart@free-electrons.com>
---
 drivers/phy/Kconfig           |   5 ++
 drivers/phy/Makefile          |   1 +
 drivers/phy/phy-berlin-sata.c | 180 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 186 insertions(+)
 create mode 100644 drivers/phy/phy-berlin-sata.c

Comments

Kishon Vijay Abraham I May 14, 2014, 10:13 a.m. UTC | #1
Hi,

On Wednesday 14 May 2014 03:18 PM, Antoine Ténart wrote:
> The Berlin SoC has a two SATA ports. Add a PHY driver to handle them.
> 
> Signed-off-by: Antoine Ténart <antoine.tenart@free-electrons.com>
> ---
>  drivers/phy/Kconfig           |   5 ++
>  drivers/phy/Makefile          |   1 +
>  drivers/phy/phy-berlin-sata.c | 180 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 186 insertions(+)
>  create mode 100644 drivers/phy/phy-berlin-sata.c
> 
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 4906c27fa3bd..b31b1986fda4 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -15,6 +15,11 @@ config GENERIC_PHY
>  	  phy users can obtain reference to the PHY. All the users of this
>  	  framework should select this config.
>  
> +config PHY_BERLIN_SATA
> +	bool
> +	depends on ARCH_BERLIN && OF
> +	select GENERIC_PHY
> +
>  config PHY_EXYNOS_MIPI_VIDEO
>  	tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver"
>  	depends on HAS_IOMEM
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index 7728518572a4..40278706ac1b 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -3,6 +3,7 @@
>  #
>  
>  obj-$(CONFIG_GENERIC_PHY)		+= phy-core.o
> +obj-$(CONFIG_PHY_BERLIN_SATA)		+= phy-berlin-sata.o
>  obj-$(CONFIG_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
>  obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
>  obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
> diff --git a/drivers/phy/phy-berlin-sata.c b/drivers/phy/phy-berlin-sata.c
> new file mode 100644
> index 000000000000..b08f76329a34
> --- /dev/null
> +++ b/drivers/phy/phy-berlin-sata.c
> @@ -0,0 +1,180 @@
> +/*
> + * Marvell Berlin SATA PHY driver
> + *
> + * Copyright (C) 2014 Marvell Technology Group Ltd.
> + *
> + * Antoine Ténart <antoine.tenart@free-electrons.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/phy/phy.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +
> +#define HOST_VSA_ADDR		0x0
> +#define HOST_VSA_DATA		0x4
> +
> +#define CONTROL_REGISTER	0x0
> +#define MBUS_SIZE_CONTROL	0x4
> +
> +#define POWER_DOWN_SATA0		BIT(6)
> +#define POWER_DOWN_SATA1		BIT(14)
> +#define MBUS_WRITE_REQUEST_SIZE_128	(BIT(2) << 16)
> +#define MBUS_READ_REQUEST_SIZE_128	(BIT(2) << 19)
> +
> +#define BERLIN_SATA_PHY_NB	2
> +
> +#define to_berlin_sata_phy_priv(desc)	\
> +	container_of((desc), struct phy_berlin_priv, phys[(desc)->index])
> +
> +struct phy_berlin_desc {
> +	struct phy	*phy;
> +	u32		val;
> +	unsigned	index;
> +};
> +
> +struct phy_berlin_priv {
> +	void __iomem	*base;
> +	spinlock_t	lock;
> +	struct phy_berlin_desc	phys[BERLIN_SATA_PHY_NB];

Can't we do away with hardcoding BERLIN_SATA_PHY_NB?
> +};
> +
> +static int phy_berlin_sata_power_on(struct phy *phy)
> +{
> +	struct phy_berlin_desc *desc = phy_get_drvdata(phy);
> +	struct phy_berlin_priv *priv = to_berlin_sata_phy_priv(desc);
> +	u32 regval;
> +
> +	spin_lock(&priv->lock);
> +
> +	/* Power up PHY */
> +	writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR);
> +	regval = readl(priv->base + HOST_VSA_DATA);
> +	regval &= ~(desc->val);
> +	writel(regval, priv->base + HOST_VSA_DATA);
> +
> +	/* Configure MBus */
> +	writel(MBUS_SIZE_CONTROL, priv->base + HOST_VSA_ADDR);
> +	regval = readl(priv->base + HOST_VSA_DATA);
> +	regval |= MBUS_WRITE_REQUEST_SIZE_128 | MBUS_READ_REQUEST_SIZE_128;
> +	writel(regval, priv->base + HOST_VSA_DATA);
> +
> +	spin_unlock(&priv->lock);
> +
> +	return 0;
> +}
> +
> +static int phy_berlin_sata_power_off(struct phy *phy)
> +{
> +	struct phy_berlin_desc *desc = phy_get_drvdata(phy);
> +	struct phy_berlin_priv *priv = to_berlin_sata_phy_priv(desc);
> +	u32 regval;
> +
> +	spin_lock(&priv->lock);
> +
> +	/* Power down PHY */
> +	writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR);
> +	regval = readl(priv->base + HOST_VSA_DATA);
> +	regval |= desc->val;
> +	writel(regval, priv->base + HOST_VSA_DATA);
> +
> +	spin_unlock(&priv->lock);
> +
> +	return 0;
> +}
> +
> +static struct phy_ops phy_berlin_sata_ops = {
> +	.power_on	= phy_berlin_sata_power_on,
> +	.power_off	= phy_berlin_sata_power_off,
> +	.owner		= THIS_MODULE,
> +};
> +
> +static struct phy_berlin_desc desc[] = {
> +	{ .val = POWER_DOWN_SATA0 },
> +	{ .val = POWER_DOWN_SATA1 },
> +	{ },
> +};
> +
> +static int phy_berlin_sata_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct phy *phy;
> +	struct phy_provider *phy_provider;
> +	struct phy_berlin_priv *priv;
> +	struct resource *res;
> +	struct device_node *child;
> +	u8 phy_id;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	priv->base = devm_ioremap(dev, res->start, resource_size(res));
> +	if (IS_ERR(priv->base))
> +		return PTR_ERR(priv->base);
> +
> +	dev_set_drvdata(dev, priv);
> +	spin_lock_init(&priv->lock);
> +
> +	for_each_child_of_node(dev->of_node, child) {
> +		if (of_property_read_u8(child, "reg", &phy_id))
> +			return -EINVAL;
> +
> +		if (phy_id >= BERLIN_SATA_PHY_NB) {
> +			dev_err(dev, "invalid reg in node %s\n", child->name);
> +			return -EINVAL;
> +		}
> +
> +		phy = devm_phy_create(dev, &phy_berlin_sata_ops, NULL);
> +		if (IS_ERR(phy)) {
> +			dev_err(dev, "failed to create PHY for node %s\n",
> +				child->name);
> +			return PTR_ERR(phy);
> +		}
> +
> +		/*
> +		 * By default the PHY node is used to request and match a PHY.
> +		 * We describe one PHY per sub-node here. Use the right node.
> +		 */
> +		phy->dev.of_node = child;
> +
> +		priv->phys[phy_id].phy = phy;
> +		priv->phys[phy_id].val = desc[phy_id].val;
> +		priv->phys[phy_id].index = phy_id;
> +		phy_set_drvdata(phy, &priv->phys[phy_id]);
> +
> +		/* Make sure the PHY is off */
> +		phy_berlin_sata_power_off(phy);
> +
> +		phy_provider = devm_of_phy_provider_register(&phy->dev,
> +							     of_phy_simple_xlate);
> +		if (IS_ERR(phy_provider))
> +			return PTR_ERR(phy_provider);

was this intentional? registering multiple PHY providers?

Thanks
Kishon
Antoine Tenart May 14, 2014, 10:21 a.m. UTC | #2
Hi,

On Wed, May 14, 2014 at 03:43:03PM +0530, Kishon Vijay Abraham I wrote:
> Hi,
> 
> On Wednesday 14 May 2014 03:18 PM, Antoine Ténart wrote:

[…]

> > +#define to_berlin_sata_phy_priv(desc)	\
> > +	container_of((desc), struct phy_berlin_priv, phys[(desc)->index])
> > +
> > +struct phy_berlin_desc {
> > +	struct phy	*phy;
> > +	u32		val;
> > +	unsigned	index;
> > +};
> > +
> > +struct phy_berlin_priv {
> > +	void __iomem	*base;
> > +	spinlock_t	lock;
> > +	struct phy_berlin_desc	phys[BERLIN_SATA_PHY_NB];
> 
> Can't we do away with hardcoding BERLIN_SATA_PHY_NB?

We can't if we want to be able to use the container_of macro in
to_berlin_sata_phy_priv(). And we want a common structure to store the
common spinlock and base address.

[…]

> > +		/*
> > +		 * By default the PHY node is used to request and match a PHY.
> > +		 * We describe one PHY per sub-node here. Use the right node.
> > +		 */
> > +		phy->dev.of_node = child;
> > +
> > +		priv->phys[phy_id].phy = phy;
> > +		priv->phys[phy_id].val = desc[phy_id].val;
> > +		priv->phys[phy_id].index = phy_id;
> > +		phy_set_drvdata(phy, &priv->phys[phy_id]);
> > +
> > +		/* Make sure the PHY is off */
> > +		phy_berlin_sata_power_off(phy);
> > +
> > +		phy_provider = devm_of_phy_provider_register(&phy->dev,
> > +							     of_phy_simple_xlate);
> > +		if (IS_ERR(phy_provider))
> > +			return PTR_ERR(phy_provider);
> 
> was this intentional? registering multiple PHY providers?

Yes. Each sub-node describe a PHY and register as a PHY provider. This
allow to reference the PHY as <&sata_phy0> and not <&sata_phy 0>. It
would be confusing to have a sub-node sata_phy0 and to use its parent
to access it.

Antoine
Arnd Bergmann May 14, 2014, 1:02 p.m. UTC | #3
On Wednesday 14 May 2014 11:48:57 Antoine Ténart wrote:
> +static int phy_berlin_sata_power_on(struct phy *phy)
> +{
> +       struct phy_berlin_desc *desc = phy_get_drvdata(phy);
> +       struct phy_berlin_priv *priv = to_berlin_sata_phy_priv(desc);
> +       u32 regval;
> +
> +       spin_lock(&priv->lock);
> +
> +       /* Power up PHY */
> +       writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR);
> +       regval = readl(priv->base + HOST_VSA_DATA);
> +       regval &= ~(desc->val);
> +       writel(regval, priv->base + HOST_VSA_DATA);
> +
> +       /* Configure MBus */
> +       writel(MBUS_SIZE_CONTROL, priv->base + HOST_VSA_ADDR);
> +       regval = readl(priv->base + HOST_VSA_DATA);
> +       regval |= MBUS_WRITE_REQUEST_SIZE_128 | MBUS_READ_REQUEST_SIZE_128;
> +       writel(regval, priv->base + HOST_VSA_DATA);
> +
> +       spin_unlock(&priv->lock);
> +
> +       return 0;
> +}
> +
> +static int phy_berlin_sata_power_off(struct phy *phy)
> +{
> +       struct phy_berlin_desc *desc = phy_get_drvdata(phy);
> +       struct phy_berlin_priv *priv = to_berlin_sata_phy_priv(desc);
> +       u32 regval;
> +
> +       spin_lock(&priv->lock);
> +
> +       /* Power down PHY */
> +       writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR);
> +       regval = readl(priv->base + HOST_VSA_DATA);
> +       regval |= desc->val;
> +       writel(regval, priv->base + HOST_VSA_DATA);
> +
> +       spin_unlock(&priv->lock);
> +
> +       return 0;

I don't get this part: you have a reference to the phy here,
but then you go poking the phy registers from the SATA driver
rather than calling a PHY API function.


> +                * By default the PHY node is used to request and match a PHY.
> +                * We describe one PHY per sub-node here. Use the right node.
> +                */
> +               phy->dev.of_node = child;
> +
> +               priv->phys[phy_id].phy = phy;
> +               priv->phys[phy_id].val = desc[phy_id].val;
> +               priv->phys[phy_id].index = phy_id;
> +               phy_set_drvdata(phy, &priv->phys[phy_id]);

And here, you set a driver specific value into a structure used by the
PHY.

Both of these are layering violations. You should either use the PHY
interfaces correctly so the SATA driver doesn't have to know about the
specific, or not use a PHY device node at all and do everything in
the SATA front-end.

	Arnd
Antoine Tenart May 14, 2014, 2:50 p.m. UTC | #4
Arnd,

On Wed, May 14, 2014 at 03:02:34PM +0200, Arnd Bergmann wrote:
> On Wednesday 14 May 2014 11:48:57 Antoine Ténart wrote:
> > +static int phy_berlin_sata_power_on(struct phy *phy)
> > +{
> > +       struct phy_berlin_desc *desc = phy_get_drvdata(phy);
> > +       struct phy_berlin_priv *priv = to_berlin_sata_phy_priv(desc);
> > +       u32 regval;
> > +
> > +       spin_lock(&priv->lock);
> > +
> > +       /* Power up PHY */
> > +       writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR);
> > +       regval = readl(priv->base + HOST_VSA_DATA);
> > +       regval &= ~(desc->val);
> > +       writel(regval, priv->base + HOST_VSA_DATA);
> > +
> > +       /* Configure MBus */
> > +       writel(MBUS_SIZE_CONTROL, priv->base + HOST_VSA_ADDR);
> > +       regval = readl(priv->base + HOST_VSA_DATA);
> > +       regval |= MBUS_WRITE_REQUEST_SIZE_128 | MBUS_READ_REQUEST_SIZE_128;
> > +       writel(regval, priv->base + HOST_VSA_DATA);
> > +
> > +       spin_unlock(&priv->lock);
> > +
> > +       return 0;
> > +}
> > +
> > +static int phy_berlin_sata_power_off(struct phy *phy)
> > +{
> > +       struct phy_berlin_desc *desc = phy_get_drvdata(phy);
> > +       struct phy_berlin_priv *priv = to_berlin_sata_phy_priv(desc);
> > +       u32 regval;
> > +
> > +       spin_lock(&priv->lock);
> > +
> > +       /* Power down PHY */
> > +       writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR);
> > +       regval = readl(priv->base + HOST_VSA_DATA);
> > +       regval |= desc->val;
> > +       writel(regval, priv->base + HOST_VSA_DATA);
> > +
> > +       spin_unlock(&priv->lock);
> > +
> > +       return 0;
> 
> I don't get this part: you have a reference to the phy here,
> but then you go poking the phy registers from the SATA driver
> rather than calling a PHY API function.

The v1 only introduced an AHCI driver. I somewhat agree the PHY
operations done in the AHCI driver could be in there.

I can move the initialization done in the AHCI driver here, but I'll
still need the driver: the Berlin AHCI needs to call the framework
generic functions with a custom mask and has custom pm_ops. So I'll
end up with a nearly empty AHCI driver, not able to control the port
parameters.

Or I can put all this in the AHCI driver, but then we'll need to
describe the PHYs there (to be able to enable each PHY independently)
and add bindings to the SATA ones.

What do you think? I prefer the first solution, but we'll have SATA
port related configuration in the PHY and a very tiny AHCI driver
because I can't really use the default behaviour of the ahci_platform.

> > +                * By default the PHY node is used to request and match a PHY.
> > +                * We describe one PHY per sub-node here. Use the right node.
> > +                */
> > +               phy->dev.of_node = child;
> > +
> > +               priv->phys[phy_id].phy = phy;
> > +               priv->phys[phy_id].val = desc[phy_id].val;
> > +               priv->phys[phy_id].index = phy_id;
> > +               phy_set_drvdata(phy, &priv->phys[phy_id]);
> 
> And here, you set a driver specific value into a structure used by the
> PHY.

Values in priv->phys[] are related to the PHYs. phy_set_drvdata() allows
to store PHY related data, which is what I'm doing there. Nearly all PHY
drivers are doing this.

Or am I missing something?

> 
> Both of these are layering violations. You should either use the PHY
> interfaces correctly so the SATA driver doesn't have to know about the
> specific, or not use a PHY device node at all and do everything in
> the SATA front-end.

To be sure: you mean using the PHY init() interface in the AHCI driver?

Antoine
Arnd Bergmann May 14, 2014, 3:31 p.m. UTC | #5
On Wednesday 14 May 2014 16:50:02 Antoine Ténart wrote:
> On Wed, May 14, 2014 at 03:02:34PM +0200, Arnd Bergmann wrote:
> > On Wednesday 14 May 2014 11:48:57 Antoine Ténart wrote:
> > > +static int phy_berlin_sata_power_on(struct phy *phy)
> > > +{
> > > +       struct phy_berlin_desc *desc = phy_get_drvdata(phy);
> > > +       struct phy_berlin_priv *priv = to_berlin_sata_phy_priv(desc);
> > > +       u32 regval;
> > > +
> > > +       spin_lock(&priv->lock);
> > > +
> > > +       /* Power up PHY */
> > > +       writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR);
> > > +       regval = readl(priv->base + HOST_VSA_DATA);
> > > +       regval &= ~(desc->val);
> > > +       writel(regval, priv->base + HOST_VSA_DATA);
> > > +
> > > +       /* Configure MBus */
> > > +       writel(MBUS_SIZE_CONTROL, priv->base + HOST_VSA_ADDR);
> > > +       regval = readl(priv->base + HOST_VSA_DATA);
> > > +       regval |= MBUS_WRITE_REQUEST_SIZE_128 | MBUS_READ_REQUEST_SIZE_128;
> > > +       writel(regval, priv->base + HOST_VSA_DATA);
> > > +
> > > +       spin_unlock(&priv->lock);
> > > +
> > > +       return 0;
> > > +}
> > > +
> > > +static int phy_berlin_sata_power_off(struct phy *phy)
> > > +{
> > > +       struct phy_berlin_desc *desc = phy_get_drvdata(phy);
> > > +       struct phy_berlin_priv *priv = to_berlin_sata_phy_priv(desc);
> > > +       u32 regval;
> > > +
> > > +       spin_lock(&priv->lock);
> > > +
> > > +       /* Power down PHY */
> > > +       writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR);
> > > +       regval = readl(priv->base + HOST_VSA_DATA);
> > > +       regval |= desc->val;
> > > +       writel(regval, priv->base + HOST_VSA_DATA);
> > > +
> > > +       spin_unlock(&priv->lock);
> > > +
> > > +       return 0;
> > 
> > I don't get this part: you have a reference to the phy here,
> > but then you go poking the phy registers from the SATA driver
> > rather than calling a PHY API function.
> 
> The v1 only introduced an AHCI driver. I somewhat agree the PHY
> operations done in the AHCI driver could be in there.
> 
> I can move the initialization done in the AHCI driver here, but I'll
> still need the driver: the Berlin AHCI needs to call the framework
> generic functions with a custom mask and has custom pm_ops. So I'll
> end up with a nearly empty AHCI driver, not able to control the port
> parameters.
> 
> Or I can put all this in the AHCI driver, but then we'll need to
> describe the PHYs there (to be able to enable each PHY independently)
> and add bindings to the SATA ones.
> 
> What do you think? I prefer the first solution, but we'll have SATA
> port related configuration in the PHY and a very tiny AHCI driver
> because I can't really use the default behaviour of the ahci_platform.

I just noticed I quoted the wrong driver with my comment, but I think
you got what I meant.

Why do you need a custom mask? Is that something you could pass
as the argument in the phy descriptor using #phy-cells=<1>?

> > > +                * By default the PHY node is used to request and match a PHY.
> > > +                * We describe one PHY per sub-node here. Use the right node.
> > > +                */
> > > +               phy->dev.of_node = child;
> > > +
> > > +               priv->phys[phy_id].phy = phy;
> > > +               priv->phys[phy_id].val = desc[phy_id].val;
> > > +               priv->phys[phy_id].index = phy_id;
> > > +               phy_set_drvdata(phy, &priv->phys[phy_id]);
> > 
> > And here, you set a driver specific value into a structure used by the
> > PHY.
> 
> Values in priv->phys[] are related to the PHYs. phy_set_drvdata() allows
> to store PHY related data, which is what I'm doing there. Nearly all PHY
> drivers are doing this.
> 
> Or am I missing something?

This part is really ok, I got confused when I replied to the wrong email.
Sorry about this.

> > Both of these are layering violations. You should either use the PHY
> > interfaces correctly so the SATA driver doesn't have to know about the
> > specific, or not use a PHY device node at all and do everything in
> > the SATA front-end.
> 
> To be sure: you mean using the PHY init() interface in the AHCI driver?

If this PHY is specific to the ahci-berlin hardware and not shared with
anything else, you don't really need to split out a phy driver. That
would somewhat simplify what you ahve here.

The alternative is to make it as generic as you can. If you can manage
to move all the phy code into phy-berlin-sata driver, it should be
possible to just extend the ahci-platform driver resume function to
reinitialize the phy if there is one.

	Arnd
Antoine Tenart May 14, 2014, 3:49 p.m. UTC | #6
On Wed, May 14, 2014 at 05:31:24PM +0200, Arnd Bergmann wrote:
> On Wednesday 14 May 2014 16:50:02 Antoine Ténart wrote:
> > On Wed, May 14, 2014 at 03:02:34PM +0200, Arnd Bergmann wrote:
> > > On Wednesday 14 May 2014 11:48:57 Antoine Ténart wrote:
> > > > +static int phy_berlin_sata_power_on(struct phy *phy)
> > > > +{
> > > > +       struct phy_berlin_desc *desc = phy_get_drvdata(phy);
> > > > +       struct phy_berlin_priv *priv = to_berlin_sata_phy_priv(desc);
> > > > +       u32 regval;
> > > > +
> > > > +       spin_lock(&priv->lock);
> > > > +
> > > > +       /* Power up PHY */
> > > > +       writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR);
> > > > +       regval = readl(priv->base + HOST_VSA_DATA);
> > > > +       regval &= ~(desc->val);
> > > > +       writel(regval, priv->base + HOST_VSA_DATA);
> > > > +
> > > > +       /* Configure MBus */
> > > > +       writel(MBUS_SIZE_CONTROL, priv->base + HOST_VSA_ADDR);
> > > > +       regval = readl(priv->base + HOST_VSA_DATA);
> > > > +       regval |= MBUS_WRITE_REQUEST_SIZE_128 | MBUS_READ_REQUEST_SIZE_128;
> > > > +       writel(regval, priv->base + HOST_VSA_DATA);
> > > > +
> > > > +       spin_unlock(&priv->lock);
> > > > +
> > > > +       return 0;
> > > > +}
> > > > +
> > > > +static int phy_berlin_sata_power_off(struct phy *phy)
> > > > +{
> > > > +       struct phy_berlin_desc *desc = phy_get_drvdata(phy);
> > > > +       struct phy_berlin_priv *priv = to_berlin_sata_phy_priv(desc);
> > > > +       u32 regval;
> > > > +
> > > > +       spin_lock(&priv->lock);
> > > > +
> > > > +       /* Power down PHY */
> > > > +       writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR);
> > > > +       regval = readl(priv->base + HOST_VSA_DATA);
> > > > +       regval |= desc->val;
> > > > +       writel(regval, priv->base + HOST_VSA_DATA);
> > > > +
> > > > +       spin_unlock(&priv->lock);
> > > > +
> > > > +       return 0;
> > > 
> > > I don't get this part: you have a reference to the phy here,
> > > but then you go poking the phy registers from the SATA driver
> > > rather than calling a PHY API function.
> > 
> > The v1 only introduced an AHCI driver. I somewhat agree the PHY
> > operations done in the AHCI driver could be in there.
> > 
> > I can move the initialization done in the AHCI driver here, but I'll
> > still need the driver: the Berlin AHCI needs to call the framework
> > generic functions with a custom mask and has custom pm_ops. So I'll
> > end up with a nearly empty AHCI driver, not able to control the port
> > parameters.
> > 
> > Or I can put all this in the AHCI driver, but then we'll need to
> > describe the PHYs there (to be able to enable each PHY independently)
> > and add bindings to the SATA ones.
> > 
> > What do you think? I prefer the first solution, but we'll have SATA
> > port related configuration in the PHY and a very tiny AHCI driver
> > because I can't really use the default behaviour of the ahci_platform.
> 
> I just noticed I quoted the wrong driver with my comment, but I think
> you got what I meant.
> 
> Why do you need a custom mask? Is that something you could pass
> as the argument in the phy descriptor using #phy-cells=<1>?

I meant a custom mask in the AHCI driver, when calling the
ahci_platform_init_host() function. Otherwise we'll have problems on the
BG2Q DMP (it only has one PHY available, and not initializing it is not
enough).

> 
> > > > +                * By default the PHY node is used to request and match a PHY.
> > > > +                * We describe one PHY per sub-node here. Use the right node.
> > > > +                */
> > > > +               phy->dev.of_node = child;
> > > > +
> > > > +               priv->phys[phy_id].phy = phy;
> > > > +               priv->phys[phy_id].val = desc[phy_id].val;
> > > > +               priv->phys[phy_id].index = phy_id;
> > > > +               phy_set_drvdata(phy, &priv->phys[phy_id]);
> > > 
> > > And here, you set a driver specific value into a structure used by the
> > > PHY.
> > 
> > Values in priv->phys[] are related to the PHYs. phy_set_drvdata() allows
> > to store PHY related data, which is what I'm doing there. Nearly all PHY
> > drivers are doing this.
> > 
> > Or am I missing something?
> 
> This part is really ok, I got confused when I replied to the wrong email.
> Sorry about this.
> 
> > > Both of these are layering violations. You should either use the PHY
> > > interfaces correctly so the SATA driver doesn't have to know about the
> > > specific, or not use a PHY device node at all and do everything in
> > > the SATA front-end.
> > 
> > To be sure: you mean using the PHY init() interface in the AHCI driver?
> 
> If this PHY is specific to the ahci-berlin hardware and not shared with
> anything else, you don't really need to split out a phy driver. That
> would somewhat simplify what you ahve here.

I don't have lots of info about that, but we set the PHY to
PHY_MODE_SATA in the AHCI driver. So I guess there are other modes.

Maybe Jisheng can help us with this?

> 
> The alternative is to make it as generic as you can. If you can manage
> to move all the phy code into phy-berlin-sata driver, it should be
> possible to just extend the ahci-platform driver resume function to
> reinitialize the phy if there is one.

It is possible to move all the PHY code the phy-berlin-sata. Then I'll
need to hack a bit the AHCI framework so it can handle more than one
PHY. But as I said, I'll still need to set a custom mask, and adding a
quirk to the AHCI platform or framework does not seem to be a very good
idea, imho.

Or I can add a computed mask to the ahci-platform driver, like I did in
the Berlin one, but I don't know what would be the consequences. For
each PHY I have:

+	mask |= 1 << i;


Antoine
Arnd Bergmann May 14, 2014, 4:11 p.m. UTC | #7
On Wednesday 14 May 2014 17:49:29 Antoine Ténart wrote:
> On Wed, May 14, 2014 at 05:31:24PM +0200, Arnd Bergmann wrote:
> > On Wednesday 14 May 2014 16:50:02 Antoine Ténart wrote:
> > > On Wed, May 14, 2014 at 03:02:34PM +0200, Arnd Bergmann wrote:
> > > > On Wednesday 14 May 2014 11:48:57 Antoine Ténart wrote:
> > > > I don't get this part: you have a reference to the phy here,
> > > > but then you go poking the phy registers from the SATA driver
> > > > rather than calling a PHY API function.
> > > 
> > > The v1 only introduced an AHCI driver. I somewhat agree the PHY
> > > operations done in the AHCI driver could be in there.
> > > 
> > > I can move the initialization done in the AHCI driver here, but I'll
> > > still need the driver: the Berlin AHCI needs to call the framework
> > > generic functions with a custom mask and has custom pm_ops. So I'll
> > > end up with a nearly empty AHCI driver, not able to control the port
> > > parameters.
> > > 
> > > Or I can put all this in the AHCI driver, but then we'll need to
> > > describe the PHYs there (to be able to enable each PHY independently)
> > > and add bindings to the SATA ones.
> > > 
> > > What do you think? I prefer the first solution, but we'll have SATA
> > > port related configuration in the PHY and a very tiny AHCI driver
> > > because I can't really use the default behaviour of the ahci_platform.
> > 
> > I just noticed I quoted the wrong driver with my comment, but I think
> > you got what I meant.
> > 
> > Why do you need a custom mask? Is that something you could pass
> > as the argument in the phy descriptor using #phy-cells=<1>?
> 
> I meant a custom mask in the AHCI driver, when calling the
> ahci_platform_init_host() function. Otherwise we'll have problems on the
> BG2Q DMP (it only has one PHY available, and not initializing it is not
> enough).

Ah, I see what you mean now. Of course, this could also be an optional
property in the generic AHCI binding, which would require that you
specify the available ports in DT for nonstandard masks.

Just to confirm: The HOST_PORTS_IMPL register on BG2Q DMP has an
value that we can't use here to determine the available ports, right?

> > > > > +                * By default the PHY node is used to request and match a PHY.
> > > > > +                * We describe one PHY per sub-node here. Use the right node.
> > > > > +                */
> > > > > +               phy->dev.of_node = child;
> > > > > +
> > > > > +               priv->phys[phy_id].phy = phy;
> > > > > +               priv->phys[phy_id].val = desc[phy_id].val;
> > > > > +               priv->phys[phy_id].index = phy_id;
> > > > > +               phy_set_drvdata(phy, &priv->phys[phy_id]);
> > > > 
> > > > And here, you set a driver specific value into a structure used by the
> > > > PHY.
> > > 
> > > Values in priv->phys[] are related to the PHYs. phy_set_drvdata() allows
> > > to store PHY related data, which is what I'm doing there. Nearly all PHY
> > > drivers are doing this.
> > > 
> > > Or am I missing something?
> > 
> > This part is really ok, I got confused when I replied to the wrong email.
> > Sorry about this.
> > 
> > > > Both of these are layering violations. You should either use the PHY
> > > > interfaces correctly so the SATA driver doesn't have to know about the
> > > > specific, or not use a PHY device node at all and do everything in
> > > > the SATA front-end.
> > > 
> > > To be sure: you mean using the PHY init() interface in the AHCI driver?
> > 
> > If this PHY is specific to the ahci-berlin hardware and not shared with
> > anything else, you don't really need to split out a phy driver. That
> > would somewhat simplify what you ahve here.
> 
> I don't have lots of info about that, but we set the PHY to
> PHY_MODE_SATA in the AHCI driver. So I guess there are other modes.

Ok, good point. This does sound a lot like there are multiple modes.

This would also imply that the "compatible" string should not have
"sata" in it either, but describe a generic PHY. You can pass the mode
as part of the phy descriptor from DT then.

> > The alternative is to make it as generic as you can. If you can manage
> > to move all the phy code into phy-berlin-sata driver, it should be
> > possible to just extend the ahci-platform driver resume function to
> > reinitialize the phy if there is one.
> 
> It is possible to move all the PHY code the phy-berlin-sata. Then I'll
> need to hack a bit the AHCI framework so it can handle more than one
> PHY. But as I said, I'll still need to set a custom mask, and adding a
> quirk to the AHCI platform or framework does not seem to be a very good
> idea, imho.
> 
> Or I can add a computed mask to the ahci-platform driver, like I did in
> the Berlin one, but I don't know what would be the consequences. For
> each PHY I have:
> 
> +	mask |= 1 << i;

It does sound generic enough that the same would be done on other
ahci-platform variants with a generic phy attached, even though
currently each one has only one phy.

We can probably define this as an extension in some form.
Do you think we need to handle the case where the first port is
unavailable but some of the other ports should be used?

	Arnd
Antoine Tenart May 14, 2014, 4:57 p.m. UTC | #8
On Wed, May 14, 2014 at 06:11:24PM +0200, Arnd Bergmann wrote:
> On Wednesday 14 May 2014 17:49:29 Antoine Ténart wrote:
> > On Wed, May 14, 2014 at 05:31:24PM +0200, Arnd Bergmann wrote:
> > > On Wednesday 14 May 2014 16:50:02 Antoine Ténart wrote:
> > > > On Wed, May 14, 2014 at 03:02:34PM +0200, Arnd Bergmann wrote:
> > > > > On Wednesday 14 May 2014 11:48:57 Antoine Ténart wrote:
> > > > > I don't get this part: you have a reference to the phy here,
> > > > > but then you go poking the phy registers from the SATA driver
> > > > > rather than calling a PHY API function.
> > > > 
> > > > The v1 only introduced an AHCI driver. I somewhat agree the PHY
> > > > operations done in the AHCI driver could be in there.
> > > > 
> > > > I can move the initialization done in the AHCI driver here, but I'll
> > > > still need the driver: the Berlin AHCI needs to call the framework
> > > > generic functions with a custom mask and has custom pm_ops. So I'll
> > > > end up with a nearly empty AHCI driver, not able to control the port
> > > > parameters.
> > > > 
> > > > Or I can put all this in the AHCI driver, but then we'll need to
> > > > describe the PHYs there (to be able to enable each PHY independently)
> > > > and add bindings to the SATA ones.
> > > > 
> > > > What do you think? I prefer the first solution, but we'll have SATA
> > > > port related configuration in the PHY and a very tiny AHCI driver
> > > > because I can't really use the default behaviour of the ahci_platform.
> > > 
> > > I just noticed I quoted the wrong driver with my comment, but I think
> > > you got what I meant.
> > > 
> > > Why do you need a custom mask? Is that something you could pass
> > > as the argument in the phy descriptor using #phy-cells=<1>?
> > 
> > I meant a custom mask in the AHCI driver, when calling the
> > ahci_platform_init_host() function. Otherwise we'll have problems on the
> > BG2Q DMP (it only has one PHY available, and not initializing it is not
> > enough).
> 
> Ah, I see what you mean now. Of course, this could also be an optional
> property in the generic AHCI binding, which would require that you
> specify the available ports in DT for nonstandard masks.
> 
> Just to confirm: The HOST_PORTS_IMPL register on BG2Q DMP has an
> value that we can't use here to determine the available ports, right?

Right. The register is here but saying there are 2 available ports,
which is true for the BG2Q SoC but not true for the BG2Q DMP board. So
the AHCI framework reads the register and performs a misconfiguration of
the SATA.

> 
> > > > > > +                * By default the PHY node is used to request and match a PHY.
> > > > > > +                * We describe one PHY per sub-node here. Use the right node.
> > > > > > +                */
> > > > > > +               phy->dev.of_node = child;
> > > > > > +
> > > > > > +               priv->phys[phy_id].phy = phy;
> > > > > > +               priv->phys[phy_id].val = desc[phy_id].val;
> > > > > > +               priv->phys[phy_id].index = phy_id;
> > > > > > +               phy_set_drvdata(phy, &priv->phys[phy_id]);
> > > > > 
> > > > > And here, you set a driver specific value into a structure used by the
> > > > > PHY.
> > > > 
> > > > Values in priv->phys[] are related to the PHYs. phy_set_drvdata() allows
> > > > to store PHY related data, which is what I'm doing there. Nearly all PHY
> > > > drivers are doing this.
> > > > 
> > > > Or am I missing something?
> > > 
> > > This part is really ok, I got confused when I replied to the wrong email.
> > > Sorry about this.
> > > 
> > > > > Both of these are layering violations. You should either use the PHY
> > > > > interfaces correctly so the SATA driver doesn't have to know about the
> > > > > specific, or not use a PHY device node at all and do everything in
> > > > > the SATA front-end.
> > > > 
> > > > To be sure: you mean using the PHY init() interface in the AHCI driver?
> > > 
> > > If this PHY is specific to the ahci-berlin hardware and not shared with
> > > anything else, you don't really need to split out a phy driver. That
> > > would somewhat simplify what you ahve here.
> > 
> > I don't have lots of info about that, but we set the PHY to
> > PHY_MODE_SATA in the AHCI driver. So I guess there are other modes.
> 
> Ok, good point. This does sound a lot like there are multiple modes.
> 
> This would also imply that the "compatible" string should not have
> "sata" in it either, but describe a generic PHY. You can pass the mode
> as part of the phy descriptor from DT then.

Yes sure, with something like:

	phys = <&foo_phy0 FOO_SATA>;

> 
> > > The alternative is to make it as generic as you can. If you can manage
> > > to move all the phy code into phy-berlin-sata driver, it should be
> > > possible to just extend the ahci-platform driver resume function to
> > > reinitialize the phy if there is one.
> > 
> > It is possible to move all the PHY code the phy-berlin-sata. Then I'll
> > need to hack a bit the AHCI framework so it can handle more than one
> > PHY. But as I said, I'll still need to set a custom mask, and adding a
> > quirk to the AHCI platform or framework does not seem to be a very good
> > idea, imho.
> > 
> > Or I can add a computed mask to the ahci-platform driver, like I did in
> > the Berlin one, but I don't know what would be the consequences. For
> > each PHY I have:
> > 
> > +	mask |= 1 << i;
> 
> It does sound generic enough that the same would be done on other
> ahci-platform variants with a generic phy attached, even though
> currently each one has only one phy.
> 
> We can probably define this as an extension in some form.
> Do you think we need to handle the case where the first port is
> unavailable but some of the other ports should be used?

The Berlin AHCI driver handles the case. I don't know if we'll come
across a use case for this but supporting it should'nt be difficult. So
why not ... :)

I think we can either add a binding enabling an automatic mask computation
in the framework or match the compatible and do this in the ahci-platform
driver. Or we can make this the default behaviour when multiple PHYs are
used in an AHCI node, but I'll have to check if that's possible.

Maybe the SATA subsystem maintainer has an opinion on the matter?


Antoine
Sebastian Hesselbarth May 14, 2014, 5:57 p.m. UTC | #9
On 05/14/2014 06:57 PM, Antoine Ténart wrote:
> On Wed, May 14, 2014 at 06:11:24PM +0200, Arnd Bergmann wrote:
>> On Wednesday 14 May 2014 17:49:29 Antoine Ténart wrote:
>>> On Wed, May 14, 2014 at 05:31:24PM +0200, Arnd Bergmann wrote:
>>>> Why do you need a custom mask? Is that something you could pass
>>>> as the argument in the phy descriptor using #phy-cells=<1>?
>>>
>>> I meant a custom mask in the AHCI driver, when calling the
>>> ahci_platform_init_host() function. Otherwise we'll have problems on the
>>> BG2Q DMP (it only has one PHY available, and not initializing it is not
>>> enough).
>>
>> Ah, I see what you mean now. Of course, this could also be an optional
>> property in the generic AHCI binding, which would require that you
>> specify the available ports in DT for nonstandard masks.
>>
>> Just to confirm: The HOST_PORTS_IMPL register on BG2Q DMP has an
>> value that we can't use here to determine the available ports, right?
> 
> Right. The register is here but saying there are 2 available ports,
> which is true for the BG2Q SoC but not true for the BG2Q DMP board. So
> the AHCI framework reads the register and performs a misconfiguration of
> the SATA.

*Disclaimer:* All PHY IP related comments below are *pure* guessing. I
have no clue how that PHY really looks like or how it is wired up.

I think it is time to sum this up a little bit and help Antoine carry
on this patches.

From what I understand from the conversation, we have a single PHY
register set dealing with both SATA ports available on the SoC.
Also, from the name of the PHY bits we assume the PHY may be able
to work in different modes than just SATA. And we currently have
an AHCI-compatible SATA IP that supports up to two ports, with one
actually connected to a SATA plug on the DMP board.

Now, thinking about the PHY binding and the (possible) multi-protocol
support, it can be possible that on BG2Q there is a generic 2-lane
LVDS PHY that can be configured to support SATA or PCIe. Both are
electrically and bit-level compatible, so they could be internally
wired-up with AHCI and PCIe controller.

From a DT point-of-view, we need a way to (a) link each SATA or PCIe
port to the PHY, (b) specify the PHY lane to be used, and (c) specify
the protocol to be used on that lane. If I got it right, Arnd already
mentioned to use the phy-specifier to deal with it:

e.g. phy = <&genphy 0 MODE_SATA> or phy = <&genphy 1 MODE_PCIE>

Let's assume we have one dual-port SATA controller and one PCIe
controller with either x1 or x2 support. The only sane DT binding,
I can think of then would be:

berlin2q.dtsi:

genphy: lvds@ea00ff {
	compatible = "marvell,berlin-lvds-phy";
	reg = <0xea00ff 0x100>;
	#phy-cells = <2>;
};

sata: sata@ab00ff {
	compatible = "ahci-platform";
	reg = <0xab00ff 0x100>;
	
	sata0: sata-port@0 {
		reg = <0>;
		phy = <&genphy 0 MODE_SATA>;
		status = "disabled";
	};

	sata1: sata-port@1 {
		reg = <1>;
		phy = <&genphy 1 MODE_SATA>;
		status = "disabled";
	};
};

pcie: pcie@ab01ff {
	compatible = "marvell,berlin-pcie";
	reg = <0xab01ff 0x100>;

	pcie0: pcie-port@0 {
		reg = <0>;
		/* set phy on a per-board basis */
		/* PCIe x1 on Lane 0 : phy = <&genphy 0 MODE_PCIE>; */
		/* PCIe x2 on Lane 0 and 1 : phy = <&genphy 0 MODE_PCIE>, <&genphy 1
MODE_PCIE>; */
		status = "disabled";
	};
};

berlin2q-dmp.dts:

&sata1 {
	status = "okay";
};

&pcie0 {
	phy = <&genphy 1 MODE_PCIE>;
};

berlin2q-foo.dts:

&pcie0 {
	phy = <&genphy 0 MODE_PCIE>, <&genphy 1 MODE_PCIE>;
};

For the driver, Antoine then would have to squeeze all PHY register
mangling in phy-berlin2.c and see how to make ahci-platform aware of
individual port nodes (I haven't looked up if it already exists, sorry)
and announce only enabled port child nodes, right?

Sebastian
Arnd Bergmann May 14, 2014, 6:12 p.m. UTC | #10
On Wednesday 14 May 2014 19:57:46 Sebastian Hesselbarth wrote:
> On 05/14/2014 06:57 PM, Antoine Ténart wrote:
> > On Wed, May 14, 2014 at 06:11:24PM +0200, Arnd Bergmann wrote:
> >> On Wednesday 14 May 2014 17:49:29 Antoine Ténart wrote:
> >>> On Wed, May 14, 2014 at 05:31:24PM +0200, Arnd Bergmann wrote:
> 
> From what I understand from the conversation, we have a single PHY
> register set dealing with both SATA ports available on the SoC.
> Also, from the name of the PHY bits we assume the PHY may be able
> to work in different modes than just SATA. And we currently have
> an AHCI-compatible SATA IP that supports up to two ports, with one
> actually connected to a SATA plug on the DMP board.
> 
> Now, thinking about the PHY binding and the (possible) multi-protocol
> support, it can be possible that on BG2Q there is a generic 2-lane
> LVDS PHY that can be configured to support SATA or PCIe. Both are
> electrically and bit-level compatible, so they could be internally
> wired-up with AHCI and PCIe controller.

Sounds like a reasonable guess. We have other PHY drivers doing the
same thing already.

> From a DT point-of-view, we need a way to (a) link each SATA or PCIe
> port to the PHY, (b) specify the PHY lane to be used, and (c) specify
> the protocol to be used on that lane. If I got it right, Arnd already
> mentioned to use the phy-specifier to deal with it:
> 
> e.g. phy = <&genphy 0 MODE_SATA> or phy = <&genphy 1 MODE_PCIE>

Right.

> Let's assume we have one dual-port SATA controller and one PCIe
> controller with either x1 or x2 support. The only sane DT binding,
> I can think of then would be:
> 
> berlin2q.dtsi:
> 
> genphy: lvds@ea00ff {
> 	compatible = "marvell,berlin-lvds-phy";
> 	reg = <0xea00ff 0x100>;
> 	#phy-cells = <2>;
> };
> 
> sata: sata@ab00ff {
> 	compatible = "ahci-platform";
> 	reg = <0xab00ff 0x100>;
> 	
> 	sata0: sata-port@0 {
> 		reg = <0>;
> 		phy = <&genphy 0 MODE_SATA>;
> 		status = "disabled";
> 	};
> 
> 	sata1: sata-port@1 {
> 		reg = <1>;
> 		phy = <&genphy 1 MODE_SATA>;
> 		status = "disabled";
> 	};
> };
> 
> pcie: pcie@ab01ff {
> 	compatible = "marvell,berlin-pcie";
> 	reg = <0xab01ff 0x100>;
> 
> 	pcie0: pcie-port@0 {
> 		reg = <0>;
> 		/* set phy on a per-board basis */
> 		/* PCIe x1 on Lane 0 : phy = <&genphy 0 MODE_PCIE>; */
> 		/* PCIe x2 on Lane 0 and 1 : phy = <&genphy 0 MODE_PCIE>, <&genphy 1
> MODE_PCIE>; */
> 		status = "disabled";
> 	};
> };
> 
> berlin2q-dmp.dts:
> 
> &sata1 {
> 	status = "okay";
> };
> 
> &pcie0 {
> 	phy = <&genphy 1 MODE_PCIE>;
> };
> 
> berlin2q-foo.dts:
> 
> &pcie0 {
> 	phy = <&genphy 0 MODE_PCIE>, <&genphy 1 MODE_PCIE>;
> };

Exactly. I would also be fine with keeping the sub-nodes of the
phy device as in v3 and using #phy-cells=<1> instead of #phy-cells.
The result would be pretty much the same, it just depends on how
closely connected the two logical phys are.

IIRC for the ST microelectronics PHY we recently reviewed, the
same PHY could be driving multiple SATA ports, or a single
multi-lane PCIe. In that case, it makes more sense to have
#phy-cells=<2>, like your example.
 
> For the driver, Antoine then would have to squeeze all PHY register
> mangling in phy-berlin2.c and see how to make ahci-platform aware of
> individual port nodes (I haven't looked up if it already exists, sorry)
> and announce only enabled port child nodes, right?

I've been thinking some more about this aspect. I don't actually have
a strong opinion on whether it's better to use the generic ahci-platform
driver, or to keep the multi-phy support as a special variant for
berlin. If we do the latter, it would however be good to define the
binding in a way that lets us later merge things into the generic phy
driver in case we get more of the same.

	Arnd
Sebastian Hesselbarth May 14, 2014, 6:42 p.m. UTC | #11
On 05/14/2014 08:12 PM, Arnd Bergmann wrote:
> On Wednesday 14 May 2014 19:57:46 Sebastian Hesselbarth wrote:
>> On 05/14/2014 06:57 PM, Antoine Ténart wrote:
>>> On Wed, May 14, 2014 at 06:11:24PM +0200, Arnd Bergmann wrote:
>>>> On Wednesday 14 May 2014 17:49:29 Antoine Ténart wrote:
>>>>> On Wed, May 14, 2014 at 05:31:24PM +0200, Arnd Bergmann wrote:
>>
>> From what I understand from the conversation, we have a single PHY
>> register set dealing with both SATA ports available on the SoC.
>> Also, from the name of the PHY bits we assume the PHY may be able
>> to work in different modes than just SATA. And we currently have
>> an AHCI-compatible SATA IP that supports up to two ports, with one
>> actually connected to a SATA plug on the DMP board.
>>
>> Now, thinking about the PHY binding and the (possible) multi-protocol
>> support, it can be possible that on BG2Q there is a generic 2-lane
>> LVDS PHY that can be configured to support SATA or PCIe. Both are
>> electrically and bit-level compatible, so they could be internally
>> wired-up with AHCI and PCIe controller.
> 
> Sounds like a reasonable guess. We have other PHY drivers doing the
> same thing already.

Well, I based that on what I know about FPGA LVDS transceivers, so
I wasn't guessing out of the blue ;)

>> From a DT point-of-view, we need a way to (a) link each SATA or PCIe
>> port to the PHY, (b) specify the PHY lane to be used, and (c) specify
>> the protocol to be used on that lane. If I got it right, Arnd already
>> mentioned to use the phy-specifier to deal with it:
>>
>> e.g. phy = <&genphy 0 MODE_SATA> or phy = <&genphy 1 MODE_PCIE>
> 
> Right.
> 
>> Let's assume we have one dual-port SATA controller and one PCIe
>> controller with either x1 or x2 support. The only sane DT binding,
>> I can think of then would be:
>>
>> berlin2q.dtsi:
>>
>> genphy: lvds@ea00ff {
>> 	compatible = "marvell,berlin-lvds-phy";
>> 	reg = <0xea00ff 0x100>;
>> 	#phy-cells = <2>;
>> };
>>
>> sata: sata@ab00ff {
>> 	compatible = "ahci-platform";
>> 	reg = <0xab00ff 0x100>;
>> 	
>> 	sata0: sata-port@0 {
>> 		reg = <0>;
>> 		phy = <&genphy 0 MODE_SATA>;
>> 		status = "disabled";
>> 	};
>>
>> 	sata1: sata-port@1 {
>> 		reg = <1>;
>> 		phy = <&genphy 1 MODE_SATA>;
>> 		status = "disabled";
>> 	};
>> };
>>
>> pcie: pcie@ab01ff {
>> 	compatible = "marvell,berlin-pcie";
>> 	reg = <0xab01ff 0x100>;
>>
>> 	pcie0: pcie-port@0 {
>> 		reg = <0>;
>> 		/* set phy on a per-board basis */
>> 		/* PCIe x1 on Lane 0 : phy = <&genphy 0 MODE_PCIE>; */
>> 		/* PCIe x2 on Lane 0 and 1 : phy = <&genphy 0 MODE_PCIE>, <&genphy 1
>> MODE_PCIE>; */
>> 		status = "disabled";
>> 	};
>> };
>>
>> berlin2q-dmp.dts:
>>
>> &sata1 {
>> 	status = "okay";
>> };
>>
>> &pcie0 {
>> 	phy = <&genphy 1 MODE_PCIE>;
>> };
>>
>> berlin2q-foo.dts:
>>
>> &pcie0 {
>> 	phy = <&genphy 0 MODE_PCIE>, <&genphy 1 MODE_PCIE>;
>> };
> 
> Exactly. I would also be fine with keeping the sub-nodes of the
> phy device as in v3 and using #phy-cells=<1> instead of #phy-cells.
> The result would be pretty much the same, it just depends on how
> closely connected the two logical phys are.
> 
> IIRC for the ST microelectronics PHY we recently reviewed, the
> same PHY could be driving multiple SATA ports, or a single
> multi-lane PCIe. In that case, it makes more sense to have
> #phy-cells=<2>, like your example.

I guess the final call is up to Kishon, but I personally prefer
#phy-cells = <2>. It makes no functional difference though.

>> For the driver, Antoine then would have to squeeze all PHY register
>> mangling in phy-berlin2.c and see how to make ahci-platform aware of
>> individual port nodes (I haven't looked up if it already exists, sorry)
>> and announce only enabled port child nodes, right?
> 
> I've been thinking some more about this aspect. I don't actually have
> a strong opinion on whether it's better to use the generic ahci-platform
> driver, or to keep the multi-phy support as a special variant for
> berlin. If we do the latter, it would however be good to define the
> binding in a way that lets us later merge things into the generic phy
> driver in case we get more of the same.

Hmm, IMHO multi-phy support is orthogonal to ahci-platform, isn't it?
ahci-platform needs to know about the phy property and calls some
helper that deals with the phy-specifier?

About a generic _phy_ driver, I am not so sure if berlin is the best
template right now ;)

So, my call would be:
- make ahci-platform aware of port sub-nodes and phy properties
- have a berlin specific PHY driver

Sebastian
Arnd Bergmann May 14, 2014, 6:51 p.m. UTC | #12
On Wednesday 14 May 2014 20:42:16 Sebastian Hesselbarth wrote:
> >> For the driver, Antoine then would have to squeeze all PHY register
> >> mangling in phy-berlin2.c and see how to make ahci-platform aware of
> >> individual port nodes (I haven't looked up if it already exists, sorry)
> >> and announce only enabled port child nodes, right?
> > 
> > I've been thinking some more about this aspect. I don't actually have
> > a strong opinion on whether it's better to use the generic ahci-platform
> > driver, or to keep the multi-phy support as a special variant for
> > berlin. If we do the latter, it would however be good to define the
> > binding in a way that lets us later merge things into the generic phy
> > driver in case we get more of the same.
> 
> Hmm, IMHO multi-phy support is orthogonal to ahci-platform, isn't it?
> ahci-platform needs to know about the phy property and calls some
> helper that deals with the phy-specifier?
> 
> About a generic _phy_ driver, I am not so sure if berlin is the best
> template right now 
> 
> So, my call would be:
> - make ahci-platform aware of port sub-nodes and phy properties
> - have a berlin specific PHY driver

I'm not sure if we need sub-nodes per port, it should be enough
to have an array of phys, plus a way to match them up with the
ports.

	Arnd
Sebastian Hesselbarth May 14, 2014, 6:56 p.m. UTC | #13
On 05/14/2014 08:51 PM, Arnd Bergmann wrote:
> On Wednesday 14 May 2014 20:42:16 Sebastian Hesselbarth wrote:
>>>> For the driver, Antoine then would have to squeeze all PHY register
>>>> mangling in phy-berlin2.c and see how to make ahci-platform aware of
>>>> individual port nodes (I haven't looked up if it already exists, sorry)
>>>> and announce only enabled port child nodes, right?
>>>
>>> I've been thinking some more about this aspect. I don't actually have
>>> a strong opinion on whether it's better to use the generic ahci-platform
>>> driver, or to keep the multi-phy support as a special variant for
>>> berlin. If we do the latter, it would however be good to define the
>>> binding in a way that lets us later merge things into the generic phy
>>> driver in case we get more of the same.
>>
>> Hmm, IMHO multi-phy support is orthogonal to ahci-platform, isn't it?
>> ahci-platform needs to know about the phy property and calls some
>> helper that deals with the phy-specifier?
>>
>> About a generic _phy_ driver, I am not so sure if berlin is the best
>> template right now 
>>
>> So, my call would be:
>> - make ahci-platform aware of port sub-nodes and phy properties
>> - have a berlin specific PHY driver
> 
> I'm not sure if we need sub-nodes per port, it should be enough
> to have an array of phys, plus a way to match them up with the
> ports.

Actually, I'd love to see sub-nodes per port as it will allow to
disabled unused ports on a per-board basis.

I have this in mind for a long time for Kirkwood's SATA node already:
Consider a board where you have the one available SATA plug connected
to port 1. How would that work out with status = "disabled"/"okay" that
doesn't allow array of strings obviously?

Sebastian
Arnd Bergmann May 14, 2014, 7:10 p.m. UTC | #14
On Wednesday 14 May 2014 20:56:29 Sebastian Hesselbarth wrote:
> On 05/14/2014 08:51 PM, Arnd Bergmann wrote:
> > On Wednesday 14 May 2014 20:42:16 Sebastian Hesselbarth wrote:
> >>>> For the driver, Antoine then would have to squeeze all PHY register
> >>>> mangling in phy-berlin2.c and see how to make ahci-platform aware of
> >>>> individual port nodes (I haven't looked up if it already exists, sorry)
> >>>> and announce only enabled port child nodes, right?
> >>>
> >>> I've been thinking some more about this aspect. I don't actually have
> >>> a strong opinion on whether it's better to use the generic ahci-platform
> >>> driver, or to keep the multi-phy support as a special variant for
> >>> berlin. If we do the latter, it would however be good to define the
> >>> binding in a way that lets us later merge things into the generic phy
> >>> driver in case we get more of the same.
> >>
> >> Hmm, IMHO multi-phy support is orthogonal to ahci-platform, isn't it?
> >> ahci-platform needs to know about the phy property and calls some
> >> helper that deals with the phy-specifier?
> >>
> >> About a generic _phy_ driver, I am not so sure if berlin is the best
> >> template right now 
> >>
> >> So, my call would be:
> >> - make ahci-platform aware of port sub-nodes and phy properties
> >> - have a berlin specific PHY driver
> > 
> > I'm not sure if we need sub-nodes per port, it should be enough
> > to have an array of phys, plus a way to match them up with the
> > ports.
> 
> Actually, I'd love to see sub-nodes per port as it will allow to
> disabled unused ports on a per-board basis.
> 
> I have this in mind for a long time for Kirkwood's SATA node already:
> Consider a board where you have the one available SATA plug connected
> to port 1. How would that work out with status = "disabled"/"okay" that
> doesn't allow array of strings obviously?

A simple bit mask would work fine, but I see your point. Doing
status="disabled" per port sounds nice.

	Arnd
Kishon Vijay Abraham I May 15, 2014, 6:45 a.m. UTC | #15
Hi,

On Thursday 15 May 2014 12:12 AM, Sebastian Hesselbarth wrote:
> On 05/14/2014 08:12 PM, Arnd Bergmann wrote:
>> On Wednesday 14 May 2014 19:57:46 Sebastian Hesselbarth wrote:
>>> On 05/14/2014 06:57 PM, Antoine Ténart wrote:
>>>> On Wed, May 14, 2014 at 06:11:24PM +0200, Arnd Bergmann wrote:
>>>>> On Wednesday 14 May 2014 17:49:29 Antoine Ténart wrote:
>>>>>> On Wed, May 14, 2014 at 05:31:24PM +0200, Arnd Bergmann wrote:
>>>
>>> From what I understand from the conversation, we have a single PHY
>>> register set dealing with both SATA ports available on the SoC.
>>> Also, from the name of the PHY bits we assume the PHY may be able
>>> to work in different modes than just SATA. And we currently have
>>> an AHCI-compatible SATA IP that supports up to two ports, with one
>>> actually connected to a SATA plug on the DMP board.
>>>
>>> Now, thinking about the PHY binding and the (possible) multi-protocol
>>> support, it can be possible that on BG2Q there is a generic 2-lane
>>> LVDS PHY that can be configured to support SATA or PCIe. Both are
>>> electrically and bit-level compatible, so they could be internally
>>> wired-up with AHCI and PCIe controller.
>>
>> Sounds like a reasonable guess. We have other PHY drivers doing the
>> same thing already.
> 
> Well, I based that on what I know about FPGA LVDS transceivers, so
> I wasn't guessing out of the blue ;)
> 
>>> From a DT point-of-view, we need a way to (a) link each SATA or PCIe
>>> port to the PHY, (b) specify the PHY lane to be used, and (c) specify
>>> the protocol to be used on that lane. If I got it right, Arnd already
>>> mentioned to use the phy-specifier to deal with it:
>>>
>>> e.g. phy = <&genphy 0 MODE_SATA> or phy = <&genphy 1 MODE_PCIE>
>>
>> Right.
>>
>>> Let's assume we have one dual-port SATA controller and one PCIe
>>> controller with either x1 or x2 support. The only sane DT binding,
>>> I can think of then would be:
>>>
>>> berlin2q.dtsi:
>>>
>>> genphy: lvds@ea00ff {
>>> 	compatible = "marvell,berlin-lvds-phy";
>>> 	reg = <0xea00ff 0x100>;
>>> 	#phy-cells = <2>;
>>> };
>>>
>>> sata: sata@ab00ff {
>>> 	compatible = "ahci-platform";
>>> 	reg = <0xab00ff 0x100>;
>>> 	
>>> 	sata0: sata-port@0 {
>>> 		reg = <0>;
>>> 		phy = <&genphy 0 MODE_SATA>;
>>> 		status = "disabled";
>>> 	};
>>>
>>> 	sata1: sata-port@1 {
>>> 		reg = <1>;
>>> 		phy = <&genphy 1 MODE_SATA>;
>>> 		status = "disabled";
>>> 	};
>>> };
>>>
>>> pcie: pcie@ab01ff {
>>> 	compatible = "marvell,berlin-pcie";
>>> 	reg = <0xab01ff 0x100>;
>>>
>>> 	pcie0: pcie-port@0 {
>>> 		reg = <0>;
>>> 		/* set phy on a per-board basis */
>>> 		/* PCIe x1 on Lane 0 : phy = <&genphy 0 MODE_PCIE>; */
>>> 		/* PCIe x2 on Lane 0 and 1 : phy = <&genphy 0 MODE_PCIE>, <&genphy 1
>>> MODE_PCIE>; */
>>> 		status = "disabled";
>>> 	};
>>> };
>>>
>>> berlin2q-dmp.dts:
>>>
>>> &sata1 {
>>> 	status = "okay";
>>> };
>>>
>>> &pcie0 {
>>> 	phy = <&genphy 1 MODE_PCIE>;
>>> };
>>>
>>> berlin2q-foo.dts:
>>>
>>> &pcie0 {
>>> 	phy = <&genphy 0 MODE_PCIE>, <&genphy 1 MODE_PCIE>;
>>> };
>>
>> Exactly. I would also be fine with keeping the sub-nodes of the
>> phy device as in v3 and using #phy-cells=<1> instead of #phy-cells.
>> The result would be pretty much the same, it just depends on how
>> closely connected the two logical phys are.

huh.. even with sub-nodes you'll need #phy-cells=<2> if we use a single *PHY
PROVIDER*. Because with just PHYs node pointer we won't be able to get the PHY.
We'll need PHY providers node pointer.

However I'd prefer to have sub-nodes for each individual PHYs and register a
single PHY PROVIDER.

Thanks
Kishon
Sebastian Hesselbarth May 15, 2014, 7:02 a.m. UTC | #16
On 05/15/2014 08:45 AM, Kishon Vijay Abraham I wrote:
> On Thursday 15 May 2014 12:12 AM, Sebastian Hesselbarth wrote:
>> On 05/14/2014 08:12 PM, Arnd Bergmann wrote:
>>> On Wednesday 14 May 2014 19:57:46 Sebastian Hesselbarth wrote:
>>>> On 05/14/2014 06:57 PM, Antoine Ténart wrote:
>>>>> On Wed, May 14, 2014 at 06:11:24PM +0200, Arnd Bergmann wrote:
>>>>>> On Wednesday 14 May 2014 17:49:29 Antoine Ténart wrote:
>>>>>>> On Wed, May 14, 2014 at 05:31:24PM +0200, Arnd Bergmann wrote:
[...]
>>>> Now, thinking about the PHY binding and the (possible) multi-protocol
>>>> support, it can be possible that on BG2Q there is a generic 2-lane
>>>> LVDS PHY that can be configured to support SATA or PCIe. Both are
>>>> electrically and bit-level compatible, so they could be internally
>>>> wired-up with AHCI and PCIe controller.
>>>
>>> Sounds like a reasonable guess. We have other PHY drivers doing the
>>> same thing already.
[...]
>>>> From a DT point-of-view, we need a way to (a) link each SATA or PCIe
>>>> port to the PHY, (b) specify the PHY lane to be used, and (c) specify
>>>> the protocol to be used on that lane. If I got it right, Arnd already
>>>> mentioned to use the phy-specifier to deal with it:
>>>>
>>>> e.g. phy = <&genphy 0 MODE_SATA> or phy = <&genphy 1 MODE_PCIE>
>>>
>>> Right.
>>>
>>>> Let's assume we have one dual-port SATA controller and one PCIe
>>>> controller with either x1 or x2 support. The only sane DT binding,
>>>> I can think of then would be:
>>>>
>>>> berlin2q.dtsi:
>>>>
>>>> genphy: lvds@ea00ff {
>>>> 	compatible = "marvell,berlin-lvds-phy";
>>>> 	reg = <0xea00ff 0x100>;
>>>> 	#phy-cells = <2>;
>>>> };
>>>>
>>>> sata: sata@ab00ff {
>>>> 	compatible = "ahci-platform";
>>>> 	reg = <0xab00ff 0x100>;
>>>> 	
>>>> 	sata0: sata-port@0 {
>>>> 		reg = <0>;
>>>> 		phy = <&genphy 0 MODE_SATA>;
>>>> 		status = "disabled";
>>>> 	};
>>>>
>>>> 	sata1: sata-port@1 {
>>>> 		reg = <1>;
>>>> 		phy = <&genphy 1 MODE_SATA>;
>>>> 		status = "disabled";
>>>> 	};
>>>> };
>>>>
>>>> pcie: pcie@ab01ff {
>>>> 	compatible = "marvell,berlin-pcie";
>>>> 	reg = <0xab01ff 0x100>;
>>>>
>>>> 	pcie0: pcie-port@0 {
>>>> 		reg = <0>;
>>>> 		/* set phy on a per-board basis */
>>>> 		/* PCIe x1 on Lane 0 : phy = <&genphy 0 MODE_PCIE>; */
>>>> 		/* PCIe x2 on Lane 0 and 1 : phy = <&genphy 0 MODE_PCIE>, <&genphy 1
>>>> MODE_PCIE>; */
>>>> 		status = "disabled";
>>>> 	};
>>>> };
>>>>
>>>> berlin2q-dmp.dts:
>>>>
>>>> &sata1 {
>>>> 	status = "okay";
>>>> };
>>>>
>>>> &pcie0 {
>>>> 	phy = <&genphy 1 MODE_PCIE>;
>>>> };
>>>>
>>>> berlin2q-foo.dts:
>>>>
>>>> &pcie0 {
>>>> 	phy = <&genphy 0 MODE_PCIE>, <&genphy 1 MODE_PCIE>;
>>>> };
>>>
>>> Exactly. I would also be fine with keeping the sub-nodes of the
>>> phy device as in v3 and using #phy-cells=<1> instead of #phy-cells.
>>> The result would be pretty much the same, it just depends on how
>>> closely connected the two logical phys are.
> 
> huh.. even with sub-nodes you'll need #phy-cells=<2> if we use a single *PHY
> PROVIDER*. Because with just PHYs node pointer we won't be able to get the PHY.
> We'll need PHY providers node pointer.
> 
> However I'd prefer to have sub-nodes for each individual PHYs and register a
> single PHY PROVIDER.

Depends on what you call PHY. In the example above the PHY is what
allows you to control both lanes.

So you want sub-nodes for each individual lane given the nomenclature
of the example?

Or like it is used in the example above, a single PHY node with an index
in the phy-specifier to pick an individual lane.

IMHO, having both phy-specifier index _and_ PHY sub-node per lane
has no benefit at all. You cannot even use the PHY sub-nodes for any
setup properties, as they depend on the consumer claiming the lane.

Sebastian
Kishon Vijay Abraham I May 15, 2014, 8:46 a.m. UTC | #17
Hi,

On Thursday 15 May 2014 12:32 PM, Sebastian Hesselbarth wrote:
> On 05/15/2014 08:45 AM, Kishon Vijay Abraham I wrote:
>> On Thursday 15 May 2014 12:12 AM, Sebastian Hesselbarth wrote:
>>> On 05/14/2014 08:12 PM, Arnd Bergmann wrote:
>>>> On Wednesday 14 May 2014 19:57:46 Sebastian Hesselbarth wrote:
>>>>> On 05/14/2014 06:57 PM, Antoine Ténart wrote:
>>>>>> On Wed, May 14, 2014 at 06:11:24PM +0200, Arnd Bergmann wrote:
>>>>>>> On Wednesday 14 May 2014 17:49:29 Antoine Ténart wrote:
>>>>>>>> On Wed, May 14, 2014 at 05:31:24PM +0200, Arnd Bergmann wrote:
> [...]
>>>>> Now, thinking about the PHY binding and the (possible) multi-protocol
>>>>> support, it can be possible that on BG2Q there is a generic 2-lane
>>>>> LVDS PHY that can be configured to support SATA or PCIe. Both are
>>>>> electrically and bit-level compatible, so they could be internally
>>>>> wired-up with AHCI and PCIe controller.
>>>>
>>>> Sounds like a reasonable guess. We have other PHY drivers doing the
>>>> same thing already.
> [...]
>>>>> From a DT point-of-view, we need a way to (a) link each SATA or PCIe
>>>>> port to the PHY, (b) specify the PHY lane to be used, and (c) specify
>>>>> the protocol to be used on that lane. If I got it right, Arnd already
>>>>> mentioned to use the phy-specifier to deal with it:
>>>>>
>>>>> e.g. phy = <&genphy 0 MODE_SATA> or phy = <&genphy 1 MODE_PCIE>
>>>>
>>>> Right.
>>>>
>>>>> Let's assume we have one dual-port SATA controller and one PCIe
>>>>> controller with either x1 or x2 support. The only sane DT binding,
>>>>> I can think of then would be:
>>>>>
>>>>> berlin2q.dtsi:
>>>>>
>>>>> genphy: lvds@ea00ff {
>>>>> 	compatible = "marvell,berlin-lvds-phy";
>>>>> 	reg = <0xea00ff 0x100>;
>>>>> 	#phy-cells = <2>;
>>>>> };
>>>>>
>>>>> sata: sata@ab00ff {
>>>>> 	compatible = "ahci-platform";
>>>>> 	reg = <0xab00ff 0x100>;
>>>>> 	
>>>>> 	sata0: sata-port@0 {
>>>>> 		reg = <0>;
>>>>> 		phy = <&genphy 0 MODE_SATA>;
>>>>> 		status = "disabled";
>>>>> 	};
>>>>>
>>>>> 	sata1: sata-port@1 {
>>>>> 		reg = <1>;
>>>>> 		phy = <&genphy 1 MODE_SATA>;
>>>>> 		status = "disabled";
>>>>> 	};
>>>>> };
>>>>>
>>>>> pcie: pcie@ab01ff {
>>>>> 	compatible = "marvell,berlin-pcie";
>>>>> 	reg = <0xab01ff 0x100>;
>>>>>
>>>>> 	pcie0: pcie-port@0 {
>>>>> 		reg = <0>;
>>>>> 		/* set phy on a per-board basis */
>>>>> 		/* PCIe x1 on Lane 0 : phy = <&genphy 0 MODE_PCIE>; */
>>>>> 		/* PCIe x2 on Lane 0 and 1 : phy = <&genphy 0 MODE_PCIE>, <&genphy 1
>>>>> MODE_PCIE>; */
>>>>> 		status = "disabled";
>>>>> 	};
>>>>> };
>>>>>
>>>>> berlin2q-dmp.dts:
>>>>>
>>>>> &sata1 {
>>>>> 	status = "okay";
>>>>> };
>>>>>
>>>>> &pcie0 {
>>>>> 	phy = <&genphy 1 MODE_PCIE>;
>>>>> };
>>>>>
>>>>> berlin2q-foo.dts:
>>>>>
>>>>> &pcie0 {
>>>>> 	phy = <&genphy 0 MODE_PCIE>, <&genphy 1 MODE_PCIE>;
>>>>> };
>>>>
>>>> Exactly. I would also be fine with keeping the sub-nodes of the
>>>> phy device as in v3 and using #phy-cells=<1> instead of #phy-cells.
>>>> The result would be pretty much the same, it just depends on how
>>>> closely connected the two logical phys are.
>>
>> huh.. even with sub-nodes you'll need #phy-cells=<2> if we use a single *PHY
>> PROVIDER*. Because with just PHYs node pointer we won't be able to get the PHY.
>> We'll need PHY providers node pointer.
>>
>> However I'd prefer to have sub-nodes for each individual PHYs and register a
>> single PHY PROVIDER.
> 
> Depends on what you call PHY. In the example above the PHY is what
> allows you to control both lanes.
> 
> So you want sub-nodes for each individual lane given the nomenclature
> of the example?
> 
> Or like it is used in the example above, a single PHY node with an index
> in the phy-specifier to pick an individual lane.
> 
> IMHO, having both phy-specifier index _and_ PHY sub-node per lane
> has no benefit at all. You cannot even use the PHY sub-nodes for any
> setup properties, as they depend on the consumer claiming the lane.

IMO the dt data should completely describe the HW. So just by looking at the
PHY node, we won't be able to tell the no of PHYs implemented in the IP if we
have a single PHY node (In this case the lanes in the IP).

However if you think it's an overkill for having sub-nodes for each lane then
single PHY node is fine too.

Thanks
Kishon
Sebastian Hesselbarth May 15, 2014, 9:17 a.m. UTC | #18
On 05/15/2014 10:46 AM, Kishon Vijay Abraham I wrote:
> On Thursday 15 May 2014 12:32 PM, Sebastian Hesselbarth wrote:
>> On 05/15/2014 08:45 AM, Kishon Vijay Abraham I wrote:
>>> On Thursday 15 May 2014 12:12 AM, Sebastian Hesselbarth wrote:
>>>> On 05/14/2014 08:12 PM, Arnd Bergmann wrote:
>>>>> On Wednesday 14 May 2014 19:57:46 Sebastian Hesselbarth wrote:
>>>>>> Let's assume we have one dual-port SATA controller and one PCIe
>>>>>> controller with either x1 or x2 support. The only sane DT binding,
>>>>>> I can think of then would be:
>>>>>>
>>>>>> berlin2q.dtsi:
>>>>>>
>>>>>> genphy: lvds@ea00ff {
>>>>>> 	compatible = "marvell,berlin-lvds-phy";
>>>>>> 	reg = <0xea00ff 0x100>;
>>>>>> 	#phy-cells = <2>;
>>>>>> };
[...]
>>
>> Depends on what you call PHY. In the example above the PHY is what
>> allows you to control both lanes.
>>
>> So you want sub-nodes for each individual lane given the nomenclature
>> of the example?
>>
>> Or like it is used in the example above, a single PHY node with an index
>> in the phy-specifier to pick an individual lane.
>>
>> IMHO, having both phy-specifier index _and_ PHY sub-node per lane
>> has no benefit at all. You cannot even use the PHY sub-nodes for any
>> setup properties, as they depend on the consumer claiming the lane.
>
> IMO the dt data should completely describe the HW. So just by looking at the
> PHY node, we won't be able to tell the no of PHYs implemented in the IP if we
> have a single PHY node (In this case the lanes in the IP).
>
> However if you think it's an overkill for having sub-nodes for each lane then
> single PHY node is fine too.

Yeah, I see your point. I just wonder how many Marvell PHYs we may hit
that require the _same_ magic setup inside but have _different_ number
of lanes. And even if, we can deal with it using a different compatible
string.

Currently, I feel a single PHY provider node and a set of compatibles
will be most likely, i.e. no per-lane sub-nodes. OTOH, the per-lane
sub-nodes is more generic as it allows us to deal PHYs that may
suddenly skip one lane in the numbering scheme. The difference for the
driver is marginal, i.e. some SoC-specific struct with a field for the
number of lanes vs. of_count_child_nodes() and a reg = <n> property for
the per-lane sub-nodes.

I used to agree to "DT should descibe HW", but with no datasheet
available, it quickly becomes fuzzy what it really looks like.

Anyway, I'll have some discussion with Antoine and Alexandre to sort out
the differences and the things in common for the PHY and SoCs in
question.

Sebastian
Kishon Vijay Abraham I May 15, 2014, 9:25 a.m. UTC | #19
On Thursday 15 May 2014 02:47 PM, Sebastian Hesselbarth wrote:
> On 05/15/2014 10:46 AM, Kishon Vijay Abraham I wrote:
>> On Thursday 15 May 2014 12:32 PM, Sebastian Hesselbarth wrote:
>>> On 05/15/2014 08:45 AM, Kishon Vijay Abraham I wrote:
>>>> On Thursday 15 May 2014 12:12 AM, Sebastian Hesselbarth wrote:
>>>>> On 05/14/2014 08:12 PM, Arnd Bergmann wrote:
>>>>>> On Wednesday 14 May 2014 19:57:46 Sebastian Hesselbarth wrote:
>>>>>>> Let's assume we have one dual-port SATA controller and one PCIe
>>>>>>> controller with either x1 or x2 support. The only sane DT binding,
>>>>>>> I can think of then would be:
>>>>>>>
>>>>>>> berlin2q.dtsi:
>>>>>>>
>>>>>>> genphy: lvds@ea00ff {
>>>>>>>     compatible = "marvell,berlin-lvds-phy";
>>>>>>>     reg = <0xea00ff 0x100>;
>>>>>>>     #phy-cells = <2>;
>>>>>>> };
> [...]
>>>
>>> Depends on what you call PHY. In the example above the PHY is what
>>> allows you to control both lanes.
>>>
>>> So you want sub-nodes for each individual lane given the nomenclature
>>> of the example?
>>>
>>> Or like it is used in the example above, a single PHY node with an index
>>> in the phy-specifier to pick an individual lane.
>>>
>>> IMHO, having both phy-specifier index _and_ PHY sub-node per lane
>>> has no benefit at all. You cannot even use the PHY sub-nodes for any
>>> setup properties, as they depend on the consumer claiming the lane.
>>
>> IMO the dt data should completely describe the HW. So just by looking at the
>> PHY node, we won't be able to tell the no of PHYs implemented in the IP if we
>> have a single PHY node (In this case the lanes in the IP).
>>
>> However if you think it's an overkill for having sub-nodes for each lane then
>> single PHY node is fine too.
> 
> Yeah, I see your point. I just wonder how many Marvell PHYs we may hit
> that require the _same_ magic setup inside but have _different_ number
> of lanes. And even if, we can deal with it using a different compatible
> string.
> 
> Currently, I feel a single PHY provider node and a set of compatibles
> will be most likely, i.e. no per-lane sub-nodes. OTOH, the per-lane
> sub-nodes is more generic as it allows us to deal PHYs that may
> suddenly skip one lane in the numbering scheme. The difference for the
> driver is marginal, i.e. some SoC-specific struct with a field for the
> number of lanes vs. of_count_child_nodes() and a reg = <n> property for
> the per-lane sub-nodes.
> 
> I used to agree to "DT should descibe HW", but with no datasheet
> available, it quickly becomes fuzzy what it really looks like.
> 
> Anyway, I'll have some discussion with Antoine and Alexandre to sort out
> the differences and the things in common for the PHY and SoCs in
> question.

cool, thanks.

-Kishon
diff mbox

Patch

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 4906c27fa3bd..b31b1986fda4 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -15,6 +15,11 @@  config GENERIC_PHY
 	  phy users can obtain reference to the PHY. All the users of this
 	  framework should select this config.
 
+config PHY_BERLIN_SATA
+	bool
+	depends on ARCH_BERLIN && OF
+	select GENERIC_PHY
+
 config PHY_EXYNOS_MIPI_VIDEO
 	tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver"
 	depends on HAS_IOMEM
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 7728518572a4..40278706ac1b 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -3,6 +3,7 @@ 
 #
 
 obj-$(CONFIG_GENERIC_PHY)		+= phy-core.o
+obj-$(CONFIG_PHY_BERLIN_SATA)		+= phy-berlin-sata.o
 obj-$(CONFIG_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
 obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
 obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
diff --git a/drivers/phy/phy-berlin-sata.c b/drivers/phy/phy-berlin-sata.c
new file mode 100644
index 000000000000..b08f76329a34
--- /dev/null
+++ b/drivers/phy/phy-berlin-sata.c
@@ -0,0 +1,180 @@ 
+/*
+ * Marvell Berlin SATA PHY driver
+ *
+ * Copyright (C) 2014 Marvell Technology Group Ltd.
+ *
+ * Antoine Ténart <antoine.tenart@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/phy/phy.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#define HOST_VSA_ADDR		0x0
+#define HOST_VSA_DATA		0x4
+
+#define CONTROL_REGISTER	0x0
+#define MBUS_SIZE_CONTROL	0x4
+
+#define POWER_DOWN_SATA0		BIT(6)
+#define POWER_DOWN_SATA1		BIT(14)
+#define MBUS_WRITE_REQUEST_SIZE_128	(BIT(2) << 16)
+#define MBUS_READ_REQUEST_SIZE_128	(BIT(2) << 19)
+
+#define BERLIN_SATA_PHY_NB	2
+
+#define to_berlin_sata_phy_priv(desc)	\
+	container_of((desc), struct phy_berlin_priv, phys[(desc)->index])
+
+struct phy_berlin_desc {
+	struct phy	*phy;
+	u32		val;
+	unsigned	index;
+};
+
+struct phy_berlin_priv {
+	void __iomem	*base;
+	spinlock_t	lock;
+	struct phy_berlin_desc	phys[BERLIN_SATA_PHY_NB];
+};
+
+static int phy_berlin_sata_power_on(struct phy *phy)
+{
+	struct phy_berlin_desc *desc = phy_get_drvdata(phy);
+	struct phy_berlin_priv *priv = to_berlin_sata_phy_priv(desc);
+	u32 regval;
+
+	spin_lock(&priv->lock);
+
+	/* Power up PHY */
+	writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR);
+	regval = readl(priv->base + HOST_VSA_DATA);
+	regval &= ~(desc->val);
+	writel(regval, priv->base + HOST_VSA_DATA);
+
+	/* Configure MBus */
+	writel(MBUS_SIZE_CONTROL, priv->base + HOST_VSA_ADDR);
+	regval = readl(priv->base + HOST_VSA_DATA);
+	regval |= MBUS_WRITE_REQUEST_SIZE_128 | MBUS_READ_REQUEST_SIZE_128;
+	writel(regval, priv->base + HOST_VSA_DATA);
+
+	spin_unlock(&priv->lock);
+
+	return 0;
+}
+
+static int phy_berlin_sata_power_off(struct phy *phy)
+{
+	struct phy_berlin_desc *desc = phy_get_drvdata(phy);
+	struct phy_berlin_priv *priv = to_berlin_sata_phy_priv(desc);
+	u32 regval;
+
+	spin_lock(&priv->lock);
+
+	/* Power down PHY */
+	writel(CONTROL_REGISTER, priv->base + HOST_VSA_ADDR);
+	regval = readl(priv->base + HOST_VSA_DATA);
+	regval |= desc->val;
+	writel(regval, priv->base + HOST_VSA_DATA);
+
+	spin_unlock(&priv->lock);
+
+	return 0;
+}
+
+static struct phy_ops phy_berlin_sata_ops = {
+	.power_on	= phy_berlin_sata_power_on,
+	.power_off	= phy_berlin_sata_power_off,
+	.owner		= THIS_MODULE,
+};
+
+static struct phy_berlin_desc desc[] = {
+	{ .val = POWER_DOWN_SATA0 },
+	{ .val = POWER_DOWN_SATA1 },
+	{ },
+};
+
+static int phy_berlin_sata_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct phy *phy;
+	struct phy_provider *phy_provider;
+	struct phy_berlin_priv *priv;
+	struct resource *res;
+	struct device_node *child;
+	u8 phy_id;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	dev_set_drvdata(dev, priv);
+	spin_lock_init(&priv->lock);
+
+	for_each_child_of_node(dev->of_node, child) {
+		if (of_property_read_u8(child, "reg", &phy_id))
+			return -EINVAL;
+
+		if (phy_id >= BERLIN_SATA_PHY_NB) {
+			dev_err(dev, "invalid reg in node %s\n", child->name);
+			return -EINVAL;
+		}
+
+		phy = devm_phy_create(dev, &phy_berlin_sata_ops, NULL);
+		if (IS_ERR(phy)) {
+			dev_err(dev, "failed to create PHY for node %s\n",
+				child->name);
+			return PTR_ERR(phy);
+		}
+
+		/*
+		 * By default the PHY node is used to request and match a PHY.
+		 * We describe one PHY per sub-node here. Use the right node.
+		 */
+		phy->dev.of_node = child;
+
+		priv->phys[phy_id].phy = phy;
+		priv->phys[phy_id].val = desc[phy_id].val;
+		priv->phys[phy_id].index = phy_id;
+		phy_set_drvdata(phy, &priv->phys[phy_id]);
+
+		/* Make sure the PHY is off */
+		phy_berlin_sata_power_off(phy);
+
+		phy_provider = devm_of_phy_provider_register(&phy->dev,
+							     of_phy_simple_xlate);
+		if (IS_ERR(phy_provider))
+			return PTR_ERR(phy_provider);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id phy_berlin_sata_of_match[] = {
+	{ .compatible = "marvell,berlin-sata-phy" },
+	{ },
+};
+
+static struct platform_driver phy_berlin_sata_driver = {
+	.probe	= phy_berlin_sata_probe,
+	.driver	= {
+		.name		= "phy-berlin-sata",
+		.owner		= THIS_MODULE,
+		.of_match_table	= phy_berlin_sata_of_match,
+	},
+};
+module_platform_driver(phy_berlin_sata_driver);
+
+MODULE_DESCRIPTION("Marvell Berlin SATA PHY driver");
+MODULE_AUTHOR("Antoine Ténart <antoine.tenart@free-electrons.com>");
+MODULE_LICENSE("GPL v2");