diff mbox

ARM: i.MX6: update KSZ9031 phy fixup

Message ID 20140403165657.510b6493@crub
State New
Headers show

Commit Message

Anatolij Gustschin April 3, 2014, 2:56 p.m. UTC
On Thu, 03 Apr 2014 16:05:47 +0200
Hubert Chaumette <hchaumette@adeneo-embedded.com> wrote:
...
> > It would be better to configure the pad skews in the board specific
> > way in the device tree. There is a binding for ksz9021 PHY in
> > Documentation/devicetree/bindings/net/micrel-ksz9021.txt.
> 
> I wonder why it it's not used in arch/arm/boot/dts/imx6q-sabrelite.dts
> instead of ksz9021rn_phy_fixup().

Probably because nobody cared to use it.

> > I have a patch for setting ksz9031rn GTX/RX CLK pad skew in a similar
> > way over device tree and plan to submit it when the net-next merge
> > window for v3.16 opens.
> 
> So, you have already implemented the ksz9031 binding ?

Partially (for GTX/RX CLK). I'm attaching a patch that I currently have.
For ksz9031rn in my DTS fec node I used:

	/* ksz9031rn: min 0, max 1860, step 60 */
        rxc-skew-ps = <1620>;
        txc-skew-ps = <1620>;

Unfortunately I'm short on time and won't be able to implement other
pad skew settings in the near future, so please fill free to extend
and push the patch.

Thanks!
diff mbox

Patch

>From 0006e3275f9c1547c5bc3c4ef23c2392ffebc20c Mon Sep 17 00:00:00 2001
From: Anatolij Gustschin <agust@denx.de>
Date: Thu, 20 Mar 2014 18:29:06 +0100
Subject: [PATCH] ARM: imx6: configure ksz90x1rn PHY pad skew settings over
 devicetree

Remove hard-coded pad skew configuration for imx6q-sabrelite
board and repace it by devicetree based configuration.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
 arch/arm/boot/dts/imx6q-sabrelite.dts |   10 +++++
 arch/arm/mach-imx/mach-imx6q.c        |   45 --------------------
 drivers/net/phy/micrel.c              |   75 ++++++++++++++++++++++++++++++++-
 3 files changed, 84 insertions(+), 46 deletions(-)

diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts
index f004913..4c27eb2 100644
--- a/arch/arm/boot/dts/imx6q-sabrelite.dts
+++ b/arch/arm/boot/dts/imx6q-sabrelite.dts
@@ -91,6 +91,16 @@ 
 	phy-mode = "rgmii";
 	phy-reset-gpios = <&gpio3 23 0>;
 	status = "okay";
+
+	/* ksz9021rn: min 0, max 3000, step 200 */
+	rxc-skew-ps = <3000>;
+	txc-skew-ps = <3000>;
+	txen-skew-ps = <0>;
+	rxdv-skew-ps = <0>;
+	rxd0-skew-ps = <0>;
+	rxd1-skew-ps = <0>;
+	rxd2-skew-ps = <0>;
+	rxd3-skew-ps = <0>;
 };
 
 &i2c1 {
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index c059843..f41d6b5 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -39,47 +39,6 @@ 
 #include "cpuidle.h"
 #include "hardware.h"
 
-/* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */
-static int ksz9021rn_phy_fixup(struct phy_device *phydev)
-{
-	if (IS_BUILTIN(CONFIG_PHYLIB)) {
-		/* min rx data delay */
-		phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL,
-			0x8000 | MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW);
-		phy_write(phydev, MICREL_KSZ9021_EXTREG_DATA_WRITE, 0x0000);
-
-		/* max rx/tx clock delay, min rx/tx control delay */
-		phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL,
-			0x8000 | MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW);
-		phy_write(phydev, MICREL_KSZ9021_EXTREG_DATA_WRITE, 0xf0f0);
-		phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL,
-			MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW);
-	}
-
-	return 0;
-}
-
-static void mmd_write_reg(struct phy_device *dev, int device, int reg, int val)
-{
-	phy_write(dev, 0x0d, device);
-	phy_write(dev, 0x0e, reg);
-	phy_write(dev, 0x0d, (1 << 14) | device);
-	phy_write(dev, 0x0e, val);
-}
-
-static int ksz9031rn_phy_fixup(struct phy_device *dev)
-{
-	/*
-	 * min rx data delay, max rx/tx clock delay,
-	 * min rx/tx control delay
-	 */
-	mmd_write_reg(dev, 2, 4, 0);
-	mmd_write_reg(dev, 2, 5, 0);
-	mmd_write_reg(dev, 2, 8, 0x003ff);
-
-	return 0;
-}
-
 /*
  * fixup for PLX PEX8909 bridge to configure GPIO1-7 as output High
  * as they are used for slots1-7 PERST#
@@ -169,10 +128,6 @@  static int ar8035_phy_fixup(struct phy_device *dev)
 static void __init imx6q_enet_phy_init(void)
 {
 	if (IS_BUILTIN(CONFIG_PHYLIB)) {
-		phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK,
-				ksz9021rn_phy_fixup);
-		phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_MASK,
-				ksz9031rn_phy_fixup);
 		phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff,
 				ar8031_phy_fixup);
 		phy_register_fixup_for_uid(PHY_ID_AR8035, 0xffffffef,
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 5a8993b..f25af72 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -242,6 +242,79 @@  static int ksz9021_config_init(struct phy_device *phydev)
 	return 0;
 }
 
+#define MII_KSZ9031RN_MMD_CTRL_REG	0x0d
+#define MII_KSZ9031RN_MMD_REGDATA_REG	0x0e
+#define OP_DATA				1
+#define KSZ9031_PS_TO_REG		60
+
+static int ksz9031_extended_write(struct phy_device *phydev,
+				  u8 mode, u32 dev_addr, u32 regnum, u16 val)
+{
+	phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, dev_addr);
+	phy_write(phydev, MII_KSZ9031RN_MMD_REGDATA_REG, regnum);
+	phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, (mode << 14) | dev_addr);
+	return phy_write(phydev, MII_KSZ9031RN_MMD_REGDATA_REG, val);
+}
+
+static int ksz9031_extended_read(struct phy_device *phydev,
+				 u8 mode, u32 dev_addr, u32 regnum)
+{
+	phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, dev_addr);
+	phy_write(phydev, MII_KSZ9031RN_MMD_REGDATA_REG, regnum);
+	phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, (mode << 14) | dev_addr);
+	return phy_read(phydev, MII_KSZ9031RN_MMD_REGDATA_REG);
+}
+
+
+static int ksz9031_load_clk_skew_values(struct phy_device *phydev,
+					struct device_node *of_node,
+					char *field1, char *field2)
+{
+	int val1 = -1;
+	int val2 = -2;
+	int newval;
+	int matches = 0;
+
+	if (!of_property_read_u32(of_node, field1, &val1))
+		matches++;
+
+	if (!of_property_read_u32(of_node, field2, &val2))
+		matches++;
+
+	if (!matches)
+		return 0;
+
+	if (matches < 2)
+		newval = ksz9031_extended_read(phydev, OP_DATA, 2, 8);
+	else
+		newval = 0;
+
+	if (val1 != -1)
+		newval = (newval & 0xffe0) |
+			 ((val1 / KSZ9031_PS_TO_REG) & 0x1f);
+
+	if (val2 != -2)
+		newval = (newval & 0xfc1f) |
+			 (((val2 / KSZ9031_PS_TO_REG) & 0x1f) << 5);
+
+	return ksz9031_extended_write(phydev, OP_DATA, 2, 8, newval);
+}
+
+static int ksz9031_config_init(struct phy_device *phydev)
+{
+	struct device *dev = &phydev->dev;
+	struct device_node *of_node = dev->of_node;
+
+	if (!of_node && dev->parent->of_node)
+		of_node = dev->parent->of_node;
+
+	if (of_node) {
+		ksz9031_load_clk_skew_values(phydev, of_node,
+				"rxc-skew-ps", "txc-skew-ps");
+	}
+	return 0;
+}
+
 #define KSZ8873MLL_GLOBAL_CONTROL_4	0x06
 #define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX	(1 << 6)
 #define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED	(1 << 4)
@@ -428,7 +501,7 @@  static struct phy_driver ksphy_driver[] = {
 	.features	= (PHY_GBIT_FEATURES | SUPPORTED_Pause
 				| SUPPORTED_Asym_Pause),
 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
-	.config_init	= kszphy_config_init,
+	.config_init	= ksz9031_config_init,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
 	.ack_interrupt	= kszphy_ack_interrupt,
-- 
1.7.9.5