diff mbox

[U-Boot,7/8] net/ethoc: don't advertise gigabit on the connected PHY

Message ID 1467992526-13417-8-git-send-email-jcmvbkbc@gmail.com
State Changes Requested
Delegated to: Tom Rini
Headers show

Commit Message

Max Filippov July 8, 2016, 3:42 p.m. UTC
Introduce MDIO communication routines. Scan MDIO bus at reset to find
attached PHYs and see if they support gigabit speeds. If they do check
their gigabit control register: if gigabit autonegotiation is enabled
clear it and reset the PHY.

This allows using OpenCores 10/100 MAC with gigabit PHY connected to
gigabit network.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
 drivers/net/ethoc.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

Comments

Simon Glass July 12, 2016, 9:56 p.m. UTC | #1
Hi Max,

On 8 July 2016 at 09:42, Max Filippov <jcmvbkbc@gmail.com> wrote:
> Introduce MDIO communication routines. Scan MDIO bus at reset to find
> attached PHYs and see if they support gigabit speeds. If they do check
> their gigabit control register: if gigabit autonegotiation is enabled
> clear it and reset the PHY.
>
> This allows using OpenCores 10/100 MAC with gigabit PHY connected to
> gigabit network.
>
> Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
> ---
>  drivers/net/ethoc.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 76 insertions(+)
>
> diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
> index ee7c01e..8f70c0c 100644
> --- a/drivers/net/ethoc.c
> +++ b/drivers/net/ethoc.c
> @@ -290,6 +290,80 @@ static int ethoc_init_ring(struct eth_device *dev)
>         return 0;
>  }
>
> +#ifdef CONFIG_SYS_ETHOC_SETUP_PHY

This should be in Kconfig.

Regards,
Simon
Michal Simek July 13, 2016, 6:28 a.m. UTC | #2
On 8.7.2016 17:42, Max Filippov wrote:
> Introduce MDIO communication routines. Scan MDIO bus at reset to find
> attached PHYs and see if they support gigabit speeds. If they do check
> their gigabit control register: if gigabit autonegotiation is enabled
> clear it and reset the PHY.
> 
> This allows using OpenCores 10/100 MAC with gigabit PHY connected to
> gigabit network.
> 
> Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
> ---
>  drivers/net/ethoc.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 76 insertions(+)
> 
> diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
> index ee7c01e..8f70c0c 100644
> --- a/drivers/net/ethoc.c
> +++ b/drivers/net/ethoc.c
> @@ -290,6 +290,80 @@ static int ethoc_init_ring(struct eth_device *dev)
>  	return 0;
>  }
>  
> +#ifdef CONFIG_SYS_ETHOC_SETUP_PHY
> +
> +static u16 ethoc_mii_read(struct eth_device *dev, u8 phy, u8 reg)
> +{
> +	ulong tmo = get_timer(0);
> +
> +	ethoc_write(dev, MIIADDRESS, MIIADDRESS_ADDR(phy, reg));
> +	ethoc_write(dev, MIICOMMAND, MIICOMMAND_READ);
> +
> +	while (get_timer(tmo) < CONFIG_SYS_HZ) {
> +		u32 status = ethoc_read(dev, MIISTATUS);
> +		if (!(status & MIISTATUS_BUSY)) {
> +			u32 data = ethoc_read(dev, MIIRX_DATA);
> +			/* reset MII command register */
> +			ethoc_write(dev, MIICOMMAND, 0);
> +			return data;
> +		}
> +	}
> +	return 0xffff;
> +}
> +
> +static void ethoc_mii_write(struct eth_device *dev, u8 phy, u8 reg, u16 v)
> +{
> +	ulong tmo = get_timer(0);
> +
> +	ethoc_write(dev, MIIADDRESS, MIIADDRESS_ADDR(phy, reg));
> +	ethoc_write(dev, MIITX_DATA, v);
> +	ethoc_write(dev, MIICOMMAND, MIICOMMAND_WRITE);
> +
> +	while (get_timer(tmo) < CONFIG_SYS_HZ) {
> +		u32 stat = ethoc_read(dev, MIISTATUS);
> +		if (!(stat & MIISTATUS_BUSY)) {
> +			/* reset MII command register */
> +			ethoc_write(dev, MIICOMMAND, 0);
> +			return;
> +		}
> +	}
> +}
> +
> +static void ethoc_setup_phy(struct eth_device *dev)
> +{
> +	u8 phy;
> +
> +	ethoc_write(dev, MIIMODER, 0xfe);
> +
> +	for (phy = 0; phy < 32; ++phy) {
> +		if (ethoc_mii_read(dev, phy, MII_PHYSID1) != 0xffff) {
> +			u16 v;
> +
> +			v = ethoc_mii_read(dev, phy, MII_BMSR);
> +			if (!(v & BMSR_ESTATEN))
> +				continue;
> +
> +			v = ethoc_mii_read(dev, phy, MII_CTRL1000);
> +			if (!(v & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)))
> +				continue;
> +
> +			ethoc_mii_write(dev, phy, MII_CTRL1000,
> +					v & ~(ADVERTISE_1000FULL |
> +					      ADVERTISE_1000HALF));
> +			v = ethoc_mii_read(dev, phy, MII_BMCR);
> +			ethoc_mii_write(dev, phy, MII_BMCR, v | BMCR_RESET);
> +		}
> +	}
> +}
> +
> +#else
> +
> +static inline void ethoc_setup_phy(struct eth_device *dev)
> +{
> +}
> +
> +#endif
> +
>  static int ethoc_reset(struct eth_device *dev)
>  {
>  	u32 mode;
> @@ -311,6 +385,8 @@ static int ethoc_reset(struct eth_device *dev)
>  	ethoc_write(dev, MODER, mode);
>  	ethoc_write(dev, IPGT, 0x15);
>  
> +	ethoc_setup_phy(dev);
> +
>  	ethoc_ack_irq(dev, INT_MASK_ALL);
>  	ethoc_enable_rx_and_tx(dev);
>  	return 0;
> 

This looks kind of weird. If you have standard phy and you do it
properly in the driver you shouldn't do it in this way.
We have the same stuff for emaclite where IP can work only at 10/100 and
it can be used with 1G phy. Just look at setting there.

Thanks,
Michal
Max Filippov July 14, 2016, 11:41 p.m. UTC | #3
Hi Simon,

On Tue, Jul 12, 2016 at 03:56:57PM -0600, Simon Glass wrote:
> On 8 July 2016 at 09:42, Max Filippov <jcmvbkbc@gmail.com> wrote:
> > Introduce MDIO communication routines. Scan MDIO bus at reset to find
> > attached PHYs and see if they support gigabit speeds. If they do check
> > their gigabit control register: if gigabit autonegotiation is enabled
> > clear it and reset the PHY.
> >
> > This allows using OpenCores 10/100 MAC with gigabit PHY connected to
> > gigabit network.
> >
> > Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
> > ---
> >  drivers/net/ethoc.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 76 insertions(+)
> >
> > diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
> > index ee7c01e..8f70c0c 100644
> > --- a/drivers/net/ethoc.c
> > +++ b/drivers/net/ethoc.c
> > @@ -290,6 +290,80 @@ static int ethoc_init_ring(struct eth_device *dev)
> >         return 0;
> >  }
> >
> > +#ifdef CONFIG_SYS_ETHOC_SETUP_PHY
> 
> This should be in Kconfig.

Ok, will add.
Max Filippov July 14, 2016, 11:51 p.m. UTC | #4
Hi Michal,

On Wed, Jul 13, 2016 at 08:28:44AM +0200, Michal Simek wrote:
> On 8.7.2016 17:42, Max Filippov wrote:
> > Introduce MDIO communication routines. Scan MDIO bus at reset to find
> > attached PHYs and see if they support gigabit speeds. If they do check
> > their gigabit control register: if gigabit autonegotiation is enabled
> > clear it and reset the PHY.
> > 
> > This allows using OpenCores 10/100 MAC with gigabit PHY connected to
> > gigabit network.
> > 
> > Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
> 
> This looks kind of weird. If you have standard phy and you do it
> properly in the driver you shouldn't do it in this way.
> We have the same stuff for emaclite where IP can work only at 10/100 and
> it can be used with 1G phy. Just look at setting there.

Ok, let me look at that.
diff mbox

Patch

diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
index ee7c01e..8f70c0c 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethoc.c
@@ -290,6 +290,80 @@  static int ethoc_init_ring(struct eth_device *dev)
 	return 0;
 }
 
+#ifdef CONFIG_SYS_ETHOC_SETUP_PHY
+
+static u16 ethoc_mii_read(struct eth_device *dev, u8 phy, u8 reg)
+{
+	ulong tmo = get_timer(0);
+
+	ethoc_write(dev, MIIADDRESS, MIIADDRESS_ADDR(phy, reg));
+	ethoc_write(dev, MIICOMMAND, MIICOMMAND_READ);
+
+	while (get_timer(tmo) < CONFIG_SYS_HZ) {
+		u32 status = ethoc_read(dev, MIISTATUS);
+		if (!(status & MIISTATUS_BUSY)) {
+			u32 data = ethoc_read(dev, MIIRX_DATA);
+			/* reset MII command register */
+			ethoc_write(dev, MIICOMMAND, 0);
+			return data;
+		}
+	}
+	return 0xffff;
+}
+
+static void ethoc_mii_write(struct eth_device *dev, u8 phy, u8 reg, u16 v)
+{
+	ulong tmo = get_timer(0);
+
+	ethoc_write(dev, MIIADDRESS, MIIADDRESS_ADDR(phy, reg));
+	ethoc_write(dev, MIITX_DATA, v);
+	ethoc_write(dev, MIICOMMAND, MIICOMMAND_WRITE);
+
+	while (get_timer(tmo) < CONFIG_SYS_HZ) {
+		u32 stat = ethoc_read(dev, MIISTATUS);
+		if (!(stat & MIISTATUS_BUSY)) {
+			/* reset MII command register */
+			ethoc_write(dev, MIICOMMAND, 0);
+			return;
+		}
+	}
+}
+
+static void ethoc_setup_phy(struct eth_device *dev)
+{
+	u8 phy;
+
+	ethoc_write(dev, MIIMODER, 0xfe);
+
+	for (phy = 0; phy < 32; ++phy) {
+		if (ethoc_mii_read(dev, phy, MII_PHYSID1) != 0xffff) {
+			u16 v;
+
+			v = ethoc_mii_read(dev, phy, MII_BMSR);
+			if (!(v & BMSR_ESTATEN))
+				continue;
+
+			v = ethoc_mii_read(dev, phy, MII_CTRL1000);
+			if (!(v & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)))
+				continue;
+
+			ethoc_mii_write(dev, phy, MII_CTRL1000,
+					v & ~(ADVERTISE_1000FULL |
+					      ADVERTISE_1000HALF));
+			v = ethoc_mii_read(dev, phy, MII_BMCR);
+			ethoc_mii_write(dev, phy, MII_BMCR, v | BMCR_RESET);
+		}
+	}
+}
+
+#else
+
+static inline void ethoc_setup_phy(struct eth_device *dev)
+{
+}
+
+#endif
+
 static int ethoc_reset(struct eth_device *dev)
 {
 	u32 mode;
@@ -311,6 +385,8 @@  static int ethoc_reset(struct eth_device *dev)
 	ethoc_write(dev, MODER, mode);
 	ethoc_write(dev, IPGT, 0x15);
 
+	ethoc_setup_phy(dev);
+
 	ethoc_ack_irq(dev, INT_MASK_ALL);
 	ethoc_enable_rx_and_tx(dev);
 	return 0;