[2/3] net: phy: vitesse: Add support for VSC73xx

Message ID 20180614123534.8063-3-linus.walleij@linaro.org
State New
Headers show
Series
  • DSA driver for Vitesse VSC73xx
Related show

Commit Message

Linus Walleij June 14, 2018, 12:35 p.m.
The VSC7385, VSC7388, VSC7395 and VSC7398 are integrated
switch/router chips for 5+1 or 8-port switches/routers. When
managed directly by Linux using DSA we need to do a special
set-up "dance" on the PHY. Unfortunately these sequences
switches the PHY to undocumented pages named 2a30 and 52b6
and does undocumented things. It is described by these opaque
sequences also in the reference manual. This is a best
effort to integrate it anyways.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

---
 drivers/net/phy/vitesse.c | 162 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 162 insertions(+)

-- 
2.17.1

Comments

Florian Fainelli June 14, 2018, 4:29 p.m. | #1
On 06/14/2018 05:35 AM, Linus Walleij wrote:
> The VSC7385, VSC7388, VSC7395 and VSC7398 are integrated

> switch/router chips for 5+1 or 8-port switches/routers. When

> managed directly by Linux using DSA we need to do a special

> set-up "dance" on the PHY. Unfortunately these sequences

> switches the PHY to undocumented pages named 2a30 and 52b6

> and does undocumented things. It is described by these opaque

> sequences also in the reference manual. This is a best

> effort to integrate it anyways.

> 

> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>


Probably as good as it can get given the information you have access to.
Maybe the guys at Mircochip could help, adding them.

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>


Just one nit below:

> ---

>  drivers/net/phy/vitesse.c | 162 ++++++++++++++++++++++++++++++++++++++

>  1 file changed, 162 insertions(+)

> 

> diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c

> index d9dd8fbfffc7..526c71ae7d96 100644

> --- a/drivers/net/phy/vitesse.c

> +++ b/drivers/net/phy/vitesse.c

> @@ -16,6 +16,7 @@

>  #include <linux/module.h>

>  #include <linux/mii.h>

>  #include <linux/ethtool.h>

> +#include <linux/delay.h>


Is that needed?
-- 
Florian
woojung.huh@microchip.com June 15, 2018, 7:24 p.m. | #2
Hi Florian,

> On 06/14/2018 05:35 AM, Linus Walleij wrote:

> > The VSC7385, VSC7388, VSC7395 and VSC7398 are integrated

> > switch/router chips for 5+1 or 8-port switches/routers. When

> > managed directly by Linux using DSA we need to do a special

> > set-up "dance" on the PHY. Unfortunately these sequences

> > switches the PHY to undocumented pages named 2a30 and 52b6

> > and does undocumented things. It is described by these opaque

> > sequences also in the reference manual. This is a best

> > effort to integrate it anyways.

> >

> > Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

> 

> Probably as good as it can get given the information you have access to.

> Maybe the guys at Mircochip could help, adding them.


Microchip have completed the acquisition of Microsemi last months. It will take some time to get access to the right data. 
Hope we can help soon.

Thanks.
Woojung

Patch

diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index d9dd8fbfffc7..526c71ae7d96 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -16,6 +16,7 @@ 
 #include <linux/module.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
+#include <linux/delay.h>
 #include <linux/phy.h>
 
 /* Vitesse Extended Page Magic Register(s) */
@@ -72,6 +73,10 @@ 
 #define PHY_ID_VSC8572			0x000704d0
 #define PHY_ID_VSC8574			0x000704a0
 #define PHY_ID_VSC8601			0x00070420
+#define PHY_ID_VSC7385			0x00070450
+#define PHY_ID_VSC7388			0x00070480
+#define PHY_ID_VSC7395			0x00070550
+#define PHY_ID_VSC7398			0x00070580
 #define PHY_ID_VSC8662			0x00070660
 #define PHY_ID_VSC8221			0x000fc550
 #define PHY_ID_VSC8211			0x000fc4b0
@@ -116,6 +121,127 @@  static int vsc824x_config_init(struct phy_device *phydev)
 	return err;
 }
 
+#define VSC73XX_EXT_PAGE_ACCESS 0x1f
+
+static int vsc73xx_read_page(struct phy_device *phydev)
+{
+	return __phy_read(phydev, VSC73XX_EXT_PAGE_ACCESS);
+}
+
+static int vsc73xx_write_page(struct phy_device *phydev, int page)
+{
+	return __phy_write(phydev, VSC73XX_EXT_PAGE_ACCESS, page);
+}
+
+static void vsc73xx_config_init(struct phy_device *phydev)
+{
+	/* Receiver init */
+	phy_write(phydev, 0x1f, 0x2a30);
+	phy_modify(phydev, 0x0c, 0x0300, 0x0200);
+	phy_write(phydev, 0x1f, 0x0000);
+
+	/* Config LEDs 0x61 */
+	phy_modify(phydev, 0x1b, 0xff00, 0x0061);
+}
+
+static int vsc738x_config_init(struct phy_device *phydev)
+{
+	u16 rev;
+	/* This magic sequence appear in the application note
+	 * "VSC7385/7388 PHY Configuration".
+	 *
+	 * Maybe one day we will get to know what it all means.
+	 */
+	phy_write(phydev, 0x1f, 0x2a30);
+	phy_modify(phydev, 0x08, 0x0200, 0x0200);
+	phy_write(phydev, 0x1f, 0x52b5);
+	phy_write(phydev, 0x10, 0xb68a);
+	phy_modify(phydev, 0x12, 0xff07, 0x0003);
+	phy_modify(phydev, 0x11, 0x00ff, 0x00a2);
+	phy_write(phydev, 0x10, 0x968a);
+	phy_write(phydev, 0x1f, 0x2a30);
+	phy_modify(phydev, 0x08, 0x0200, 0x0000);
+	phy_write(phydev, 0x1f, 0x0000);
+
+	/* Read revision */
+	rev = phy_read(phydev, 0x03);
+	rev &= 0x0f;
+
+	/* Special quirk for revision 0 */
+	if (rev == 0) {
+		phy_write(phydev, 0x1f, 0x2a30);
+		phy_modify(phydev, 0x08, 0x0200, 0x0200);
+		phy_write(phydev, 0x1f, 0x52b5);
+		phy_write(phydev, 0x12, 0x0000);
+		phy_write(phydev, 0x11, 0x0689);
+		phy_write(phydev, 0x10, 0x8f92);
+		phy_write(phydev, 0x1f, 0x52b5);
+		phy_write(phydev, 0x12, 0x0000);
+		phy_write(phydev, 0x11, 0x0e35);
+		phy_write(phydev, 0x10, 0x9786);
+		phy_write(phydev, 0x1f, 0x2a30);
+		phy_modify(phydev, 0x08, 0x0200, 0x0000);
+		phy_write(phydev, 0x17, 0xff80);
+		phy_write(phydev, 0x17, 0x0000);
+	}
+
+	phy_write(phydev, 0x1f, 0x0000);
+	phy_write(phydev, 0x12, 0x0048);
+
+	if (rev == 0) {
+		phy_write(phydev, 0x1f, 0x2a30);
+		phy_write(phydev, 0x14, 0x6600);
+		phy_write(phydev, 0x1f, 0x0000);
+		phy_write(phydev, 0x18, 0xa24e);
+	} else {
+		phy_write(phydev, 0x1f, 0x2a30);
+		phy_modify(phydev, 0x16, 0x0fc0, 0x0240);
+		phy_modify(phydev, 0x14, 0x6000, 0x4000);
+		/* bits 14-15 in extended register 0x14 controls DACG amplitude
+		 * 6 = -8%, 2 is hardware default
+		 */
+		phy_write(phydev, 0x1f, 0x0001);
+		phy_modify(phydev, 0x14, 0xe000, 0x6000);
+		phy_write(phydev, 0x1f, 0x0000);
+	}
+
+	vsc73xx_config_init(phydev);
+
+	return genphy_config_init(phydev);
+}
+
+static int vsc739x_config_init(struct phy_device *phydev)
+{
+	/* This magic sequence appears in the VSC7395 SparX-G5e application
+	 * note "VSC7395/VSC7398 PHY Configuration"
+	 *
+	 * Maybe one day we will get to know what it all means.
+	 */
+	phy_write(phydev, 0x1f, 0x2a30);
+	phy_modify(phydev, 0x08, 0x0200, 0x0200);
+	phy_write(phydev, 0x1f, 0x52b5);
+	phy_write(phydev, 0x10, 0xb68a);
+	phy_modify(phydev, 0x12, 0xff07, 0x0003);
+	phy_modify(phydev, 0x11, 0x00ff, 0x00a2);
+	phy_write(phydev, 0x10, 0x968a);
+	phy_write(phydev, 0x1f, 0x2a30);
+	phy_modify(phydev, 0x08, 0x0200, 0x0000);
+	phy_write(phydev, 0x1f, 0x0000);
+
+	phy_write(phydev, 0x1f, 0x0000);
+	phy_write(phydev, 0x12, 0x0048);
+	phy_write(phydev, 0x1f, 0x2a30);
+	phy_modify(phydev, 0x16, 0x0fc0, 0x0240);
+	phy_modify(phydev, 0x14, 0x6000, 0x4000);
+	phy_write(phydev, 0x1f, 0x0001);
+	phy_modify(phydev, 0x14, 0xe000, 0x6000);
+	phy_write(phydev, 0x1f, 0x0000);
+
+	vsc73xx_config_init(phydev);
+
+	return genphy_config_init(phydev);
+}
+
 /* This adds a skew for both TX and RX clocks, so the skew should only be
  * applied to "rgmii-id" interfaces. It may not work as expected
  * on "rgmii-txid", "rgmii-rxid" or "rgmii" interfaces. */
@@ -318,6 +444,38 @@  static struct phy_driver vsc82xx_driver[] = {
 	.config_init    = &vsc8601_config_init,
 	.ack_interrupt  = &vsc824x_ack_interrupt,
 	.config_intr    = &vsc82xx_config_intr,
+}, {
+	.phy_id         = PHY_ID_VSC7385,
+	.name           = "Vitesse VSC7385",
+	.phy_id_mask    = 0x000ffff0,
+	.features       = PHY_GBIT_FEATURES,
+	.config_init    = vsc738x_config_init,
+	.read_page      = vsc73xx_read_page,
+	.write_page     = vsc73xx_write_page,
+}, {
+	.phy_id         = PHY_ID_VSC7388,
+	.name           = "Vitesse VSC7388",
+	.phy_id_mask    = 0x000ffff0,
+	.features       = PHY_GBIT_FEATURES,
+	.config_init    = vsc738x_config_init,
+	.read_page      = vsc73xx_read_page,
+	.write_page     = vsc73xx_write_page,
+}, {
+	.phy_id         = PHY_ID_VSC7395,
+	.name           = "Vitesse VSC7395",
+	.phy_id_mask    = 0x000ffff0,
+	.features       = PHY_GBIT_FEATURES,
+	.config_init    = vsc739x_config_init,
+	.read_page      = vsc73xx_read_page,
+	.write_page     = vsc73xx_write_page,
+}, {
+	.phy_id         = PHY_ID_VSC7398,
+	.name           = "Vitesse VSC7398",
+	.phy_id_mask    = 0x000ffff0,
+	.features       = PHY_GBIT_FEATURES,
+	.config_init    = vsc739x_config_init,
+	.read_page      = vsc73xx_read_page,
+	.write_page     = vsc73xx_write_page,
 }, {
 	.phy_id         = PHY_ID_VSC8662,
 	.name           = "Vitesse VSC8662",
@@ -358,6 +516,10 @@  static struct mdio_device_id __maybe_unused vitesse_tbl[] = {
 	{ PHY_ID_VSC8514, 0x000ffff0 },
 	{ PHY_ID_VSC8572, 0x000ffff0 },
 	{ PHY_ID_VSC8574, 0x000ffff0 },
+	{ PHY_ID_VSC7385, 0x000ffff0 },
+	{ PHY_ID_VSC7388, 0x000ffff0 },
+	{ PHY_ID_VSC7395, 0x000ffff0 },
+	{ PHY_ID_VSC7398, 0x000ffff0 },
 	{ PHY_ID_VSC8662, 0x000ffff0 },
 	{ PHY_ID_VSC8221, 0x000ffff0 },
 	{ PHY_ID_VSC8211, 0x000ffff0 },