All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-15 14:25 ` WingMan Kwok
  0 siblings, 0 replies; 63+ messages in thread
From: WingMan Kwok @ 2015-10-15 14:25 UTC (permalink / raw
  To: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, kishon,
	rogerq, m-karicheri2, bhelgaas, ssantosh, linux, devicetree,
	linux-kernel, linux-pci, linux-arm-kernel
  Cc: WingMan Kwok

On TI's Keystone platforms, several peripherals such as the
gbe ethernet switch, 10gbe ethether switch and PCIe controller
require the use of a SerDes for converting SoC parallel data into
serialized data that can be output over a high-speed electrical
interface, and also converting high-speed serial input data
into parallel data that can be processed by the SoC.  The
SerDeses used by those peripherals, though they may be different,
are largely similar in functionality and setup.

This patch series provides a SerDes phy driver implementation that can be
used by the above mentioned peripheral drivers to configure their
respective SerDeses.

As an example of the using the SerDes driver, this patch series also
updates the Keystone PCIe host driver to enable and use its SerDes block.

References:
[1] KeyStone II Architecture Serializer/Deserializer (SerDes) User's Guide
    (http://www.ti.com/lit/ug/spruho3a/spruho3a.pdf)

v1: 
	- addresses the following review comments
		1. https://lkml.org/lkml/2015/10/13/803
		2. https://lkml.org/lkml/2015/10/14/613
		3. https://lkml.org/lkml/2015/10/13/818

	- An update to PCIe dts bindings to enable the PCIe SerDes is
	  submitted in a separate patch.

WingMan Kwok (2):
  phy: keystone: serdes driver for gbe 10gbe and pcie
  PCI: keystone: update to use generic keystone serdes driver

 Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
 drivers/pci/host/pci-keystone.c                  |   54 +-
 drivers/pci/host/pci-keystone.h                  |    2 +
 drivers/phy/Kconfig                              |    8 +
 drivers/phy/Makefile                             |    1 +
 drivers/phy/phy-keystone-serdes.c                | 2373 ++++++++++++++++++++++
 6 files changed, 2707 insertions(+), 9 deletions(-)
 create mode 100644 drivers/phy/phy-keystone-serdes.c

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-15 14:25 ` WingMan Kwok
  0 siblings, 0 replies; 63+ messages in thread
From: WingMan Kwok @ 2015-10-15 14:25 UTC (permalink / raw
  To: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, kishon,
	rogerq, m-karicheri2, bhelgaas, ssantosh, linux, devicetree,
	linux-kernel, linux-pci, linux-arm-kernel
  Cc: WingMan Kwok

On TI's Keystone platforms, several peripherals such as the
gbe ethernet switch, 10gbe ethether switch and PCIe controller
require the use of a SerDes for converting SoC parallel data into
serialized data that can be output over a high-speed electrical
interface, and also converting high-speed serial input data
into parallel data that can be processed by the SoC.  The
SerDeses used by those peripherals, though they may be different,
are largely similar in functionality and setup.

This patch series provides a SerDes phy driver implementation that can be
used by the above mentioned peripheral drivers to configure their
respective SerDeses.

As an example of the using the SerDes driver, this patch series also
updates the Keystone PCIe host driver to enable and use its SerDes block.

References:
[1] KeyStone II Architecture Serializer/Deserializer (SerDes) User's Guide
    (http://www.ti.com/lit/ug/spruho3a/spruho3a.pdf)

v1: 
	- addresses the following review comments
		1. https://lkml.org/lkml/2015/10/13/803
		2. https://lkml.org/lkml/2015/10/14/613
		3. https://lkml.org/lkml/2015/10/13/818

	- An update to PCIe dts bindings to enable the PCIe SerDes is
	  submitted in a separate patch.

WingMan Kwok (2):
  phy: keystone: serdes driver for gbe 10gbe and pcie
  PCI: keystone: update to use generic keystone serdes driver

 Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
 drivers/pci/host/pci-keystone.c                  |   54 +-
 drivers/pci/host/pci-keystone.h                  |    2 +
 drivers/phy/Kconfig                              |    8 +
 drivers/phy/Makefile                             |    1 +
 drivers/phy/phy-keystone-serdes.c                | 2373 ++++++++++++++++++++++
 6 files changed, 2707 insertions(+), 9 deletions(-)
 create mode 100644 drivers/phy/phy-keystone-serdes.c

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-15 14:25 ` WingMan Kwok
  0 siblings, 0 replies; 63+ messages in thread
From: WingMan Kwok @ 2015-10-15 14:25 UTC (permalink / raw
  To: linux-arm-kernel

On TI's Keystone platforms, several peripherals such as the
gbe ethernet switch, 10gbe ethether switch and PCIe controller
require the use of a SerDes for converting SoC parallel data into
serialized data that can be output over a high-speed electrical
interface, and also converting high-speed serial input data
into parallel data that can be processed by the SoC.  The
SerDeses used by those peripherals, though they may be different,
are largely similar in functionality and setup.

This patch series provides a SerDes phy driver implementation that can be
used by the above mentioned peripheral drivers to configure their
respective SerDeses.

As an example of the using the SerDes driver, this patch series also
updates the Keystone PCIe host driver to enable and use its SerDes block.

References:
[1] KeyStone II Architecture Serializer/Deserializer (SerDes) User's Guide
    (http://www.ti.com/lit/ug/spruho3a/spruho3a.pdf)

v1: 
	- addresses the following review comments
		1. https://lkml.org/lkml/2015/10/13/803
		2. https://lkml.org/lkml/2015/10/14/613
		3. https://lkml.org/lkml/2015/10/13/818

	- An update to PCIe dts bindings to enable the PCIe SerDes is
	  submitted in a separate patch.

WingMan Kwok (2):
  phy: keystone: serdes driver for gbe 10gbe and pcie
  PCI: keystone: update to use generic keystone serdes driver

 Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
 drivers/pci/host/pci-keystone.c                  |   54 +-
 drivers/pci/host/pci-keystone.h                  |    2 +
 drivers/phy/Kconfig                              |    8 +
 drivers/phy/Makefile                             |    1 +
 drivers/phy/phy-keystone-serdes.c                | 2373 ++++++++++++++++++++++
 6 files changed, 2707 insertions(+), 9 deletions(-)
 create mode 100644 drivers/phy/phy-keystone-serdes.c

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-15 14:25 ` WingMan Kwok
  (?)
@ 2015-10-15 14:25   ` WingMan Kwok
  -1 siblings, 0 replies; 63+ messages in thread
From: WingMan Kwok @ 2015-10-15 14:25 UTC (permalink / raw
  To: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, kishon,
	rogerq, m-karicheri2, bhelgaas, ssantosh, linux, devicetree,
	linux-kernel, linux-pci, linux-arm-kernel
  Cc: WingMan Kwok

On TI's Keystone platforms, several peripherals such as the
gbe ethernet switch, 10gbe ethernet switch and PCIe controller
require the use of a SerDes for converting SoC parallel data into
serialized data that can be output over a high-speed electrical
interface, and also converting high-speed serial input data
into parallel data that can be processed by the SoC.  The
SerDeses used by those peripherals, though they may be different,
are largely similar in functionality and setup.

This patch provides a SerDes phy driver implementation that can be
used by the above mentioned peripheral drivers to configure their
respective SerDeses.

v1:
	- see cover letter for review comments addressed.

Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
---
 Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
 drivers/phy/Kconfig                              |    8 +
 drivers/phy/Makefile                             |    1 +
 drivers/phy/phy-keystone-serdes.c                | 2373 ++++++++++++++++++++++
 4 files changed, 2660 insertions(+)
 create mode 100644 drivers/phy/phy-keystone-serdes.c

diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt
index 9cf9446..4dca271 100644
--- a/Documentation/devicetree/bindings/phy/ti-phy.txt
+++ b/Documentation/devicetree/bindings/phy/ti-phy.txt
@@ -115,4 +115,282 @@ sata_phy: phy@4A096000 {
 	clock-names = "sysclk", "refclk";
 	syscon-pllreset = <&scm_conf 0x3fc>;
 	#phy-cells = <0>;
+
+TI Keystone SerDes PHY
+======================
+
+Required properties:
+ - compatible: should be one of
+	* "ti,keystone-serdes-gbe"
+	* "ti,keystone-serdes-xgbe"
+	* "ti,keystone-serdes-pcie"
+ - reg:
+	* base address and length of the SerDes register set
+ - reg-names:
+	* "serdes"
+		- name of the reg SerDes register set
+ - #phy-cells:
+	* From the generic phy bindings, must be 0;
+ - num-lanes:
+	* Number of lanes in SerDes.
+
+Optional properties:
+ - syscon-peripheral:
+	* Handle to the subsystem register region of the peripheral
+	  inside which the SerDes exists.
+ - syscon-link:
+	* Handle to the Link register region of the peripheral inside
+	  which the SerDes exists.  Example: it is the PCSR register
+	  region in the case of 10gbe.
+ - rx-force-enable:
+	* Include this property if receiver attenuation and boost are
+	  to be configured with specific values defined in rx-force.
+ - link-rate-kbps:
+	* SerDes link rate to be configured, in kbps.
+
+
+For gbe and 10gbe SerDes, it is optional to represent each lane as
+a sub-node, which can be enabled or disabled individually using
+the "status" property.
+
+Required properties (lane sub-node):
+ - reg:
+	* lane number
+
+Optional properties (lane sub-node):
+ - control-rate:
+	* Lane control rate
+		0: full rate
+		1: half rate
+		2: quarter rate
+ - rx-start:
+	* Initial lane rx equalizer attenuation and boost configurations.
+	* Must be array of 2 integers.
+ - rx-force:
+	* Forced lane rx equalizer attenuation and boost configurations.
+	* Must be array of 2 integers.
+ - tx-coeff:
+	* Lane c1, c2, cm, attenuation and regulator output voltage
+	  configurations.
+	* Must be array of 5 integers.
+ - loopback:
+	* Include this property to enable loopback at the SerDes
+	  lane level.
+
+Example for Keystone K2E GBE:
+-----------------------------
+
+gbe_serdes0: gbe_serdes@232a000 {
+	#phy-cells		= <0>;
+	compatible		= "ti,keystone-serdes-gbe";
+	reg			= <0x0232a000 0x2000>;
+	reg-names		= "serdes";
+	link-rate-kbps		= <1250000>;
+	num-lanes		= <4>;
+	lanes {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		lane@0 {
+			/*loopback;*/
+			reg		= <0>;
+			control-rate	= <2>; /* quart */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <0 0 0 12 4>;
+			       /* c1 c2 cm att vreg */
+		};
+		lane@1 {
+			/*loopback;*/
+			reg		= <1>;
+			control-rate	= <2>; /* quart */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <0 0 0 12 4>;
+			       /* c1 c2 cm att vreg */
+		};
+	};
+};
+
+gbe_serdes1: gbe_serdes@2324000 {
+	#phy-cells		= <0>;
+	compatible		= "ti,keystone-serdes-gbe";
+	reg			= <0x02324000 0x2000>;
+	reg-names		= "serdes";
+	link-rate-kbps		= <1250000>;
+	num-lanes		= <4>;
+	lanes {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		lane@0 {
+			/*loopback;*/
+			reg		= <0>;
+			control-rate	= <2>; /* quart */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <0 0 0 12 4>;
+			       /* c1 c2 cm att vreg */
+		};
+		lane@1 {
+			/*loopback;*/
+			reg		= <1>;
+			control-rate	= <2>; /* quart */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <0 0 0 12 4>;
+			       /* c1 c2 cm att vreg */
+		};
+	};
+};
+
+netcp: netcp@24000000 {
+	...
+
+	netcp-devices {
+		...
+
+		gbe@200000 { /* ETHSS */
+			...
+			serdeses {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				serdes@0 {
+					reg = <0>;
+					phys = <&gbe_serdes0>;
+					status = "ok";
+				};
+				serdes@1 {
+					reg = <1>;
+					phys = <&gbe_serdes1>;
+					status = "ok";
+				};
+
+			...
+			};
+
+		...
+		};
+
+	...
+	};
+};
+
+Example for Keystone PCIE:
+--------------------------
+
+	pcie0_phy: serdes_phy@2320000 {
+		#phy-cells = <0>;
+		compatible = "ti,keystone-serdes-pcie";
+		reg = <0x02320000 0x4000>;
+		reg-names = "serdes";
+		num-lanes = <2>;
+	};
+
+
+Then the PHY can be used in PCIe controller node as
+
+	pcie0: pcie@21800000 {
+		...
+
+		serdeses {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			serdes@0 {
+				reg = <0>;
+				phys = <&pcie0_phy>;
+				status = "disabled";
+			};
+		};
+	}
+
+Example for K2E 10GBE:
+----------------------
+
+Define the syscon regmaps for 10gbe subsystem:
+
+xgbe_subsys: xgbe_subsys@2f00000 {
+	status		= "ok";
+	compatible	= "syscon";
+	reg		= <0x02f00000 0x100>;
+};
+
+Define the syscon regmaps for 10gbe pcsr:
+
+xgbe_pcsr: xgbe_pcsr@2f00000 {
+	status		= "ok";
+	compatible	= "syscon";
+	reg		= <0x02f00600 0x100>;
+};
+
+Define the 10gbe SerDes node:
+
+xgbe_serdes: xgbe_serdes@231e000 {
+	status			= "ok";
+	#phy-cells		= <0>;
+	compatible		= "ti,keystone-serdes-xgbe";
+	reg			= <0x0231e000 0x2000>;
+	reg-names		= "serdes";
+	link-rate-kbps		= <10312500>;
+	num-lanes		= <2>;
+	syscon-peripheral	= <&xgbe_subsys>;
+	syscon-link		= <&xgbe_pcsr>;
+	lanes {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		lane@0 {
+			/*loopback;*/
+			reg		= <0>;
+			control-rate	= <0>; /* full */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <2 0 0 12 4>;
+				/* c1 c2 cm att vreg */
+		};
+		lane@1 {
+			/*loopback;*/
+			reg		= <1>;
+			control-rate	= <0>; /* full */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <2 0 0 12 4>;
+				/* c1 c2 cm att vreg */
+		};
+	};
+};
+
+Then the 10gbe SerDes PHY can be used in the 10gbe switch node:
+
+netcpx: netcpx@2f00000 {
+
+	...
+
+	netcp-devices {
+
+		...
+
+		xgbe@2f00000 {
+
+			...
+
+			syscon-subsys = <&xgbe_subsys>;
+			syscon-link = <&xgbe_pcsr>;
+
+			...
+
+			serdeses {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				serdes@0 {
+					reg = <0>;
+					phys = <&xgbe_serdes>;
+				};
+			};
+
+
+			...
+
+		};
+	};
+
+	...
+
 };
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 47da573..8fc21a4 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -118,6 +118,14 @@ config PHY_RCAR_GEN2
 	help
 	  Support for USB PHY found on Renesas R-Car generation 2 SoCs.
 
+config PHY_TI_KEYSTONE_SERDES
+	tristate "TI Keystone SerDes PHY support"
+	depends on OF && ARCH_KEYSTONE
+	select GENERIC_PHY
+	help
+	  This option enables support for TI Keystone SerDes PHY found
+	  in peripherals GBE, 10GBE and PCIe.
+
 config OMAP_CONTROL_PHY
 	tristate "OMAP CONTROL PHY Driver"
 	depends on ARCH_OMAP2PLUS || COMPILE_TEST
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index a5b18c1..8cb365b 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -46,3 +46,4 @@ obj-$(CONFIG_PHY_QCOM_UFS) 	+= phy-qcom-ufs-qmp-14nm.o
 obj-$(CONFIG_PHY_TUSB1210)		+= phy-tusb1210.o
 obj-$(CONFIG_PHY_BRCMSTB_SATA)		+= phy-brcmstb-sata.o
 obj-$(CONFIG_PHY_PISTACHIO_USB)		+= phy-pistachio-usb.o
+obj-$(CONFIG_PHY_TI_KEYSTONE_SERDES)	+= phy-keystone-serdes.o
diff --git a/drivers/phy/phy-keystone-serdes.c b/drivers/phy/phy-keystone-serdes.c
new file mode 100644
index 0000000..f213006
--- /dev/null
+++ b/drivers/phy/phy-keystone-serdes.c
@@ -0,0 +1,2373 @@
+/*
+ * Texas Instruments Keystone SerDes driver
+ * Authors: WingMan Kwok <w-kwok2@ti.com>
+ *
+ * This is the SerDes Phy driver for Keystone devices. This is
+ * required to support PCIe RC functionality based on designware
+ * PCIe hardware, gbe and 10gbe found on these devices.
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The contents of the array k2_100mhz_pcie_5gbps_serdes is covered by BSD
+ * license.
+ */
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/firmware.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+/*
+ * Keystone2 SERDES registers
+ */
+/* 0x1fc0 - 0x1fff */
+#define KSERDES_SS_OFFSET	0x1fc0
+/* 0x1fc0 */
+#define MOD_VER_REG		(KSERDES_SS_OFFSET + 0x00)
+/* 0x1fc4 */
+#define MEM_ADR_REG		(KSERDES_SS_OFFSET + 0x04)
+/* 0x1fc8 */
+#define MEM_DAT_REG		(KSERDES_SS_OFFSET + 0x08)
+/* 0x1fcc */
+#define MEM_DATINC_REG		(KSERDES_SS_OFFSET + 0x0c)
+/* 0x1fd0 */
+#define CPU_CTRL_REG		(KSERDES_SS_OFFSET + 0x10)
+/* 0x1fe0, 0x1fe4 */
+#define LANE_CTRL_STS_REG(x)	(KSERDES_SS_OFFSET + 0x20 + (x * 0x04))
+/* 0x1ff0 */
+#define LINK_LOSS_WAIT_REG	(KSERDES_SS_OFFSET + 0x30)
+/* 0x1ff4 */
+#define PLL_CTRL_REG		(KSERDES_SS_OFFSET + 0x34)
+
+/* CMU0 SS 0x0000 - 0x01ff */
+#define CMU0_SS_OFFSET		0x0000
+#define CMU0_REG(x)		(CMU0_SS_OFFSET + x)
+
+/* LANE SS 0x0200 - 0x03ff, 0x0400 - 0x05ff, ... */
+#define LANE0_SS_OFFSET		0x0200
+#define LANEX_SS_OFFSET(x)	(LANE0_SS_OFFSET * (x + 1))
+#define LANEX_REG(x, y)		(LANEX_SS_OFFSET(x) + y)
+
+/* CML SS 0x0a00 - 0x0bff */
+#define CML_SS_OFFSET		0x0a00
+#define CML_REG(x)		(CML_SS_OFFSET + x)
+
+/* CMU1 SS 0x0c00 - 0x0dff */
+#define CMU1_SS_OFFSET		0x0c00
+#define CMU1_REG(x)		(CMU1_SS_OFFSET + x)
+
+/*
+ * XGE PCS-R registers
+ */
+#define PCSR_OFFSET(x)		(x * 0x80)
+
+#define PCSR_TX_CTL(x)		(PCSR_OFFSET(x) + 0x00)
+#define PCSR_TX_STATUS(x)	(PCSR_OFFSET(x) + 0x04)
+#define PCSR_RX_CTL(x)		(PCSR_OFFSET(x) + 0x08)
+#define PCSR_RX_STATUS(x)	(PCSR_OFFSET(x) + 0x0C)
+
+#define XGE_CTRL_OFFSET		0x0c
+#define PCIE_PL_GEN2_OFFSET	0x180c
+
+#define reg_rmw(addr, value, mask) \
+	__raw_writel(((__raw_readl(addr) & (~(mask))) | \
+			(value & (mask))), (addr))
+
+/* Replaces bit field [msb:lsb] in register located
+ * at (base + offset) by val
+ */
+#define FINSR(base, offset, msb, lsb, val) \
+	reg_rmw((base) + (offset), ((val) << (lsb)), GENMASK((msb), (lsb)))
+
+/* This version of FEXTR is NOT safe for msb = 31, lsb = 0
+ * but then why would we need FEXTR for that case.
+ */
+#define FEXTR(val, msb, lsb) \
+	(((val) >> (lsb)) & ((1 << ((msb) - (lsb) + 1)) - 1))
+
+#define MOD_VER(serdes) \
+	((kserdes_readl(serdes, MOD_VER_REG) >> 16) & 0xffff)
+
+#define PHY_A(serdes) (MOD_VER(serdes) != 0x4eba)
+
+#define FOUR_LANE(serdes) \
+	((MOD_VER(serdes) == 0x4eb9) || (MOD_VER(serdes) == 0x4ebd))
+
+#define LANE_ENABLE(sc, n) ((sc)->lane[n].enable)
+
+#define for_each_enable_lane(func, sc)			\
+	do {						\
+		int i;					\
+		for (i = 0; i < (sc)->lanes; i++) {	\
+			if (!LANE_ENABLE((sc), i))	\
+				continue;		\
+							\
+			(func)((sc), i);		\
+		}					\
+	} while (0)
+
+#define for_each_lane(func, sc)				\
+	do {						\
+		int i;					\
+		for (i = 0; i < (sc)->lanes; i++) {	\
+			(func)((sc), i);		\
+		}					\
+	} while (0)
+
+#define for_each_enable_lane_return(func, sc, r)	\
+	do {						\
+		int i;					\
+		(r) = 0;				\
+		for (i = 0; i < (sc)->lanes; i++) {	\
+			if (!LANE_ENABLE((sc), i))	\
+				continue;		\
+							\
+			(r) = (func)((sc), i);		\
+			if ((r))			\
+				break;			\
+		}					\
+	} while (0)
+
+#define MAX_COMPARATORS			5
+#define DFE_OFFSET_SAMPLES		100
+
+/* CPU CTRL bits */
+#define CPU_EN			BIT(31)
+#define CPU_GO			BIT(30)
+#define POR_EN			BIT(29)
+#define CPUREG_EN		BIT(28)
+#define AUTONEG_CTL		BIT(27)
+#define DATASPLIT		BIT(26)
+#define LNKTRN_SIG_DET		BIT(8)
+
+#define ANEG_LINK_CTL_10GKR_MASK	GENMASK(21, 20)
+#define ANEG_LINK_CTL_1GKX_MASK		GENMASK(17, 16)
+#define ANEG_LINK_CTL_1G10G_MASK \
+	(ANEG_LINK_CTL_10GKR_MASK | ANEG_LINK_CTL_1GKX_MASK)
+
+#define ANEG_1G_10G_OPT_MASK		GENMASK(7, 5)
+
+#define SERDES_REG_INDEX		0
+
+/* SERDES internal memory */
+#define KSERDES_XFW_MEM_SIZE		SZ_64K
+#define KSERDES_XFW_CONFIG_MEM_SIZE	SZ_64
+#define KSERDES_XFW_NUM_PARAMS		5
+
+/* Last 64B of the 64KB internal mem is for parameters */
+#define KSERDES_XFW_CONFIG_START_ADDR \
+	(KSERDES_XFW_MEM_SIZE - KSERDES_XFW_CONFIG_MEM_SIZE)
+
+#define KSERDES_XFW_PARAM_START_ADDR \
+	(KSERDES_XFW_MEM_SIZE - (KSERDES_XFW_NUM_PARAMS * 4))
+
+/* All firmware file names end up here. List the firmware file names below.
+ * Newest first. Search starts from the 0-th array entry until a firmware
+ * file is found.
+ */
+const char *ks2_gbe_serdes_firmwares[] = {"ks2_gbe_serdes.bin"};
+const char *ks2_xgbe_serdes_firmwares[] = {"ks2_xgbe_serdes.bin"};
+const char *ks2_pcie_serdes_firmwares[] = {"ks2_pcie_serdes.bin"};
+
+/* SERDES Link Rate Kbps */
+enum KSERDES_LINK_RATE {
+	KSERDES_LINK_RATE_1P25G		=  1250000,
+	KSERDES_LINK_RATE_3P125G	=  3125000,
+	KSERDES_LINK_RATE_4P9152G	=  4915200,
+	KSERDES_LINK_RATE_5G		=  5000000,
+	KSERDES_LINK_RATE_6P144G	=  6144000,
+	KSERDES_LINK_RATE_6P25G		=  6250000,
+	KSERDES_LINK_RATE_7P3728G	=  7372800,
+	KSERDES_LINK_RATE_9P8304G	=  9830400,
+	KSERDES_LINK_RATE_10G		= 10000000,
+	KSERDES_LINK_RATE_10P3125G	= 10312500,
+	KSERDES_LINK_RATE_12P5G		= 12500000,
+};
+
+/* SERDES Lane Control Rate */
+enum KSERDES_LANE_CTRL_RATE {
+	KSERDES_FULL_RATE,
+	KSERDES_HALF_RATE,
+	KSERDES_QUARTER_RATE,
+};
+
+enum KSERDES_PHY_TYPE {
+	KSERDES_PHY_SGMII,
+	KSERDES_PHY_XGE,
+	KSERDES_PHY_PCIE,
+	KSERDES_PHY_HYPERLINK,
+};
+
+struct kserdes_tx_coeff {
+	u32	c1;
+	u32	c2;
+	u32	cm;
+	u32	att;
+	u32	vreg;
+};
+
+struct kserdes_equalizer {
+	u32	att;
+	u32	boost;
+};
+
+struct kserdes_lane_config {
+	bool				enable;
+	u32				ctrl_rate;
+	struct kserdes_tx_coeff		tx_coeff;
+	struct kserdes_equalizer	rx_start;
+	struct kserdes_equalizer	rx_force;
+	bool				loopback;
+};
+
+#define KSERDES_MAX_LANES		4
+
+struct kserdes_fw_config {
+	bool				on;
+	u32				rate;
+	u32				link_loss_wait;
+	u32				lane_seeds;
+	u32				fast_train;
+	u32				active_lane;
+	u32				c1, c2, cm, attn, boost, dlpf, cdrcal;
+	u32				lane_config[KSERDES_MAX_LANES];
+};
+
+struct kserdes_config {
+	struct device			*dev;
+	enum KSERDES_PHY_TYPE		phy_type;
+	u32				lanes;
+	void __iomem			*regs;
+	struct regmap			*peripheral_regmap;
+	struct regmap			*pcsr_regmap;
+	/* non-fw specific */
+	const char			*init_fw;
+	struct serdes_cfg		*init_cfg;
+	int				init_cfg_len;
+	enum KSERDES_LINK_RATE		link_rate;
+	bool				rx_force_enable;
+	struct kserdes_lane_config	lane[KSERDES_MAX_LANES];
+	/* fw specific */
+	bool				firmware;
+	struct kserdes_fw_config	fw;
+};
+
+struct kserdes_dev {
+	struct device *dev;
+	struct phy *phy;
+	struct kserdes_config sc;
+};
+
+struct kserdes_comparator_tap_offsets {
+	u32 cmp;
+	u32 tap1;
+	u32 tap2;
+	u32 tap3;
+	u32 tap4;
+	u32 tap5;
+};
+
+struct kserdes_lane_offsets {
+	struct kserdes_comparator_tap_offsets ct_ofs[MAX_COMPARATORS];
+};
+
+struct kserdes_offsets {
+	struct kserdes_lane_offsets lane_ofs[KSERDES_MAX_LANES];
+};
+
+struct serdes_cfg {
+	u32 ofs;
+	u32 msb;
+	u32 lsb;
+	u32 val;
+};
+
+static inline u32 kserdes_readl(void __iomem *base, u32 offset)
+{
+	return readl(base + offset);
+}
+
+static inline void kserdes_writel(void __iomem *base, u32 offset, u32 value)
+{
+	writel(value, base + offset);
+}
+
+static void kserdes_do_config(void __iomem *base,
+			      struct serdes_cfg *cfg, u32 size)
+{
+	u32 i;
+
+	for (i = 0; i < size; i++)
+		FINSR(base, cfg[i].ofs, cfg[i].msb, cfg[i].lsb, cfg[i].val);
+}
+
+static int kserdes_load_init_fw(struct kserdes_config *sc,
+				const char **a_firmwares,
+				int n_firmwares)
+{
+	const struct firmware *fw;
+	bool found = false;
+	int ret, i;
+
+	for (i = 0; i < n_firmwares; i++) {
+		if (a_firmwares[i]) {
+			ret = request_firmware(&fw, a_firmwares[i], sc->dev);
+			if (!ret) {
+				found = true;
+				break;
+			}
+		}
+	}
+
+	if (!found) {
+		dev_err(sc->dev, "can't get any serdes init fw");
+		return -ENODEV;
+	}
+
+	sc->init_fw = a_firmwares[i];
+	sc->init_cfg = devm_kzalloc(sc->dev, fw->size, GFP_KERNEL);
+	memcpy((void *)sc->init_cfg, fw->data,  fw->size);
+	sc->init_cfg_len = fw->size;
+	release_firmware(fw);
+
+	kserdes_do_config(sc->regs, sc->init_cfg,
+			  sc->init_cfg_len / sizeof(struct serdes_cfg));
+
+	return 0;
+}
+
+static inline u32 _kserdes_read_tbus_val(void __iomem *sregs)
+{
+	u32 tmp;
+
+	if (PHY_A(sregs)) {
+		tmp  = ((kserdes_readl(sregs, CMU0_REG(0xec))) >> 24) & 0x0ff;
+		tmp |= ((kserdes_readl(sregs, CMU0_REG(0xfc))) >> 16) & 0xf00;
+	} else {
+		tmp  = ((kserdes_readl(sregs, CMU0_REG(0xf8))) >> 16) & 0xfff;
+	}
+
+	return tmp;
+}
+
+static void _kserdes_write_tbus_addr(void __iomem *sregs, int select, int ofs)
+{
+	if (select && !FOUR_LANE(sregs))
+		++select;
+
+	if (PHY_A(sregs))
+		FINSR(sregs, CMU0_REG(0x8), 31, 24, ((select << 5) + ofs));
+	else
+		FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((select << 8) + ofs));
+}
+
+static u32 _kserdes_read_select_tbus(void __iomem *sregs, int select, int ofs)
+{
+	/* set tbus address */
+	_kserdes_write_tbus_addr(sregs, select, ofs);
+	/* get tbus value */
+	return _kserdes_read_tbus_val(sregs);
+}
+
+static inline void kserdes_tap1_patch(struct kserdes_config *sc)
+{
+	FINSR(sc->regs, CML_REG(0xbc), 28, 24, 0x1e);
+}
+
+static inline void kserdes_set_tx_idle(struct kserdes_config *sc, u32 lane)
+{
+	if (sc->phy_type != KSERDES_PHY_XGE)
+		FINSR(sc->regs, LANEX_REG(lane, 0xb8), 17, 16, 3);
+
+	FINSR(sc->regs, LANE_CTRL_STS_REG(lane), 25, 24, 3);
+	FINSR(sc->regs, LANEX_REG(lane, 0x28), 21, 20, 0);
+}
+
+static inline void kserdes_clr_tx_idle(struct kserdes_config *sc, u32 lane)
+{
+	if (sc->phy_type != KSERDES_PHY_XGE)
+		FINSR(sc->regs, LANEX_REG(lane, 0xb8), 17, 16, 0);
+
+	FINSR(sc->regs, LANE_CTRL_STS_REG(lane), 25, 24, 0);
+	FINSR(sc->regs, LANEX_REG(lane, 0x28), 21, 20, 0);
+}
+
+static inline void kserdes_cdfe_enable(struct kserdes_config *sc, u32 lane)
+{
+	FINSR(sc->regs, LANEX_REG(lane, 0x94), 24, 24, 0x1);
+}
+
+static inline void kserdes_cdfe_force_calibration_enable(
+			struct kserdes_config *sc, u32 lane)
+{
+	FINSR(sc->regs, LANEX_REG(lane, 0x98), 0, 0, 0x1);
+}
+
+static void kserdes_phya_lane_patch(struct kserdes_config *sc, u32 lane)
+{
+	/* pma_ln_vreg */
+	FINSR(sc->regs, LANEX_REG(lane, 0x18), 25, 24, 0x2);
+	/* pma_ln_vregh */
+	FINSR(sc->regs, LANEX_REG(lane, 0x18), 27, 26, 0x2);
+	/* pma_int_step */
+	FINSR(sc->regs, LANEX_REG(lane, 0x14), 15, 13, 0x1);
+	/* turn off att_boost */
+	FINSR(sc->regs, LANEX_REG(lane, 0x4c), 19, 16, 0xf);
+	/* set dfe_bias to 10 */
+	FINSR(sc->regs, LANEX_REG(lane, 0x4c), 23, 20, 0xa);
+	/* Set offset average num of samples to max value */
+	FINSR(sc->regs, LANEX_REG(lane, 0x78), 30, 24, 0x7f);
+}
+
+static void kserdes_phyb_patch(struct kserdes_config *sc)
+{
+	/* Enables the Center DFE */
+	for_each_enable_lane(kserdes_cdfe_enable, sc);
+
+	/* setting initial cdfe */
+	FINSR(sc->regs, CML_REG(0x108), 23, 16, 0x04);
+
+	/* setting rx tap */
+	FINSR(sc->regs, CML_REG(0xbc), 28, 24, 0x0);
+
+	/* enable cdfe_ln_force_cal for cdfe */
+	for_each_lane(kserdes_cdfe_force_calibration_enable, sc);
+}
+
+static inline void kserdes_set_lane_starts(struct kserdes_config *sc, u32 lane)
+{
+	/* att start -1 for short channel */
+	FINSR(sc->regs, LANEX_REG(lane, 0x8c), 11, 8,
+	      sc->lane[lane].rx_start.att);
+	/* boost start -3 for short channel */
+	FINSR(sc->regs, LANEX_REG(lane, 0x8c), 15, 12,
+	      sc->lane[lane].rx_start.boost);
+}
+
+static void kserdes_phy_patch(struct kserdes_config *sc)
+{
+	if (sc->phy_type == KSERDES_PHY_XGE)
+		kserdes_phyb_patch(sc);
+	else if (sc->link_rate >= KSERDES_LINK_RATE_9P8304G)
+		for_each_enable_lane(kserdes_phya_lane_patch, sc);
+
+	/* Set ATT and BOOST start values for each lane */
+	for_each_enable_lane(kserdes_set_lane_starts, sc);
+}
+
+static inline void _kserdes_set_training_pattern(void __iomem *sregs)
+{
+	FINSR(sregs, CML_REG(0xc8), 5, 0, 0x0f);
+}
+
+static void kserdes_set_lane_overrides(struct kserdes_config *sc, u32 lane)
+{
+	u32 val_0, val_1, val;
+
+	/* read laneX_ctrl_i/laneX_pd_i */
+	val_0 = _kserdes_read_select_tbus(sc->regs, lane + 1, 0);
+
+	/* read laneX_rate_i */
+	val_1 = _kserdes_read_select_tbus(sc->regs, lane + 1, 1);
+
+	/* set RESET state */
+	val = 0;
+	/* user rate */
+	val |= ((val_1 >> 9) & 0x3) << 1;
+	/* user PD */
+	val |= (val_0 & 0x3) << 3;
+	/* user ctrl_i */
+	val |= ((val_0 >> 2) & 0x1ff) << 5;
+	/* set override */
+	val |= (1 << 14);
+	/* try claer TX Valid bits */
+	val &= ~0x60;
+
+	/* Only modify the reset bit and the overlay bit */
+	FINSR(sc->regs, LANEX_REG(lane, 0x028), 29, 15, val);
+}
+
+static inline void kserdes_assert_reset(struct kserdes_config *sc)
+{
+	for_each_enable_lane(kserdes_set_lane_overrides, sc);
+}
+
+static inline void kserdes_config_c1_c2_cm(struct kserdes_config *sc, u32 lane)
+{
+	u32 c1, c2, cm;
+
+	c1 = sc->lane[lane].tx_coeff.c1;
+	c2 = sc->lane[lane].tx_coeff.c2;
+	cm = sc->lane[lane].tx_coeff.cm;
+
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		/* TX Control override enable */
+		FINSR(sc->regs, LANEX_REG(lane, 0x8), 11,  8, (cm & 0xf));
+		FINSR(sc->regs, LANEX_REG(lane, 0x8),  4,  0, (c1 & 0x1f));
+		FINSR(sc->regs, LANEX_REG(lane, 0x8),  7,  5, (c2 & 0x7));
+		FINSR(sc->regs, LANEX_REG(lane, 0x4),
+		      18, 18, ((c2 >> 3) & 0x1));
+	} else {
+		FINSR(sc->regs, LANEX_REG(lane, 0x8), 15, 12, (cm & 0xf));
+		FINSR(sc->regs, LANEX_REG(lane, 0x8),  4,  0, (c1 & 0x1f));
+		FINSR(sc->regs, LANEX_REG(lane, 0x8), 11,  8, (c2 & 0xf));
+	}
+}
+
+static inline void kserdes_config_att_boost(struct kserdes_config *sc, u32 lane)
+{
+	u32 att, boost;
+
+	att = sc->lane[lane].rx_force.att;
+	boost = sc->lane[lane].rx_force.boost;
+
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		FINSR(sc->regs, LANEX_REG(lane, 0x98), 13, 13, 0);
+		FINSR(sc->regs, LANEX_REG(lane, 0x8c), 15, 12, boost);
+		FINSR(sc->regs, LANEX_REG(lane, 0x8c), 11, 8, att);
+	} else {
+		if (att != 1) {
+			FINSR(sc->regs, CML_REG(0x84), 0, 0, 0);
+			FINSR(sc->regs, CML_REG(0x8c), 24, 24, 0);
+			FINSR(sc->regs, LANEX_REG(lane, 0x8c), 11, 8, att);
+		}
+		if (boost != 1) {
+			FINSR(sc->regs, CML_REG(0x84), 1, 1, 0);
+			FINSR(sc->regs, CML_REG(0x8c), 25, 25, 0);
+			FINSR(sc->regs, LANEX_REG(lane, 0x8c), 15, 12, boost);
+		}
+	}
+}
+
+static void kserdes_set_tx_rx_fir_coeff(struct kserdes_config *sc, u32 lane)
+{
+	struct kserdes_tx_coeff *tc = &sc->lane[lane].tx_coeff;
+
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		/* Tx Swing */
+		FINSR(sc->regs, LANEX_REG(lane, 0x004), 29, 26, tc->att);
+		/* Regulator voltage */
+		FINSR(sc->regs, LANEX_REG(lane, 0x0a4), 2, 0, tc->vreg);
+	} else {
+		/* Tx Swing */
+		FINSR(sc->regs, LANEX_REG(lane, 0x004), 28, 25, tc->att);
+		/* Regulator voltage */
+		FINSR(sc->regs, LANEX_REG(lane, 0x084), 7, 5, tc->vreg);
+	}
+
+	kserdes_config_c1_c2_cm(sc, lane);
+
+	if (sc->rx_force_enable)
+		kserdes_config_att_boost(sc, lane);
+}
+
+static inline void _kserdes_force_signal_detect_low(
+				void __iomem *sregs, u32 lane)
+{
+	FINSR(sregs, LANEX_REG(lane, 0x004), 2, 1, 0x2);
+}
+
+static inline void kserdes_force_signal_detect_low(
+			struct kserdes_config *sc, u32 lane)
+{
+	_kserdes_force_signal_detect_low(sc->regs, lane);
+}
+
+static inline void _kserdes_force_signal_detect_high(
+				void __iomem *sregs, u32 lane)
+{
+	FINSR(sregs, LANEX_REG(lane, 0x004), 2, 1, 0x0);
+}
+
+static inline void kserdes_force_signal_detect_high(
+			struct kserdes_config *sc, u32 lane)
+{
+	_kserdes_force_signal_detect_high(sc->regs, lane);
+}
+
+static int kserdes_deassert_reset_poll_others(struct kserdes_config *sc)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(500);
+	u32 lanes_not_ok = 0;
+	u32 ofs = 28;
+	u32 ret, i;
+
+	/* assume all enable lanes not-ok (1) and all others
+	 * ok (0) to start
+	 */
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		lanes_not_ok |= (1 << i);
+	}
+
+	/* This is not a mistake.  For 2-laner, we
+	 * check bit 29 and 30,  NOT 28 and 29.
+	 */
+	if (!FOUR_LANE(sc->regs))
+		ofs = 29;
+
+	do {
+		for (i = 0; i < sc->lanes; i++) {
+			if (!LANE_ENABLE(sc, i))
+				continue;
+
+			/* no need to check again if this lane's status
+			 * is already good
+			 */
+			if (!(lanes_not_ok & (1 << i)))
+				continue;
+
+			ret = kserdes_readl(sc->regs, CML_REG(0x1f8));
+
+			/* clear corresponding lane_not_ok bit if
+			 * status is good (1)
+			 */
+			if (ret & BIT(ofs + i))
+				lanes_not_ok &= ~(1 << i);
+		}
+
+		/* get out if all lanes are good to go */
+		if (!lanes_not_ok)
+			return 0;
+
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+
+		cpu_relax();
+	} while (true);
+}
+
+static int kserdes_deassert_reset_poll_pcie(struct kserdes_config *sc)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(500);
+	u32 lanes_not_ok = 0;
+	u32 ret, i;
+
+	/* assume all enable lanes not-ok (1) and all others
+	 * ok (0) to start
+	 */
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		lanes_not_ok |= (1 << i);
+	}
+
+	do {
+		for (i = 0; i < sc->lanes; i++) {
+			if (!LANE_ENABLE(sc, i))
+				continue;
+
+			/* no need to check again if this lane's status
+			 * is already good
+			 */
+			if (!(lanes_not_ok & (1 << i)))
+				continue;
+
+			ret = _kserdes_read_select_tbus(sc->regs, i + 1, 0x02);
+
+			/* clear corresponding lane_not_ok bit if
+			 * status is good (0)
+			 */
+			if (!(ret & BIT(4)))
+				lanes_not_ok &= ~(1 << i);
+		}
+
+		/* get out if all lanes are good to go */
+		if (!lanes_not_ok)
+			return 0;
+
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+
+		cpu_relax();
+	} while (true);
+}
+
+static inline void _kserdes_lane_reset(void __iomem *serdes,
+				       u32 lane, u32 reset)
+{
+	if (reset)
+		FINSR(serdes, LANEX_REG(lane, 0x28), 29, 29, 0x1);
+	else
+		FINSR(serdes, LANEX_REG(lane, 0x28), 29, 29, 0x0);
+}
+
+static inline void kserdes_release_reset(struct kserdes_config *sc, u32 lane)
+{
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		/* set pma_cmu_sel to 1 */
+		FINSR(sc->regs, LANEX_REG(lane, 0x60), 0, 0, 0x1);
+	}
+	/* release reset */
+	_kserdes_lane_reset(sc->regs, lane, 0);
+}
+
+static int kserdes_deassert_reset(struct kserdes_config *sc, u32 poll)
+{
+	int ret = 0;
+
+	for_each_enable_lane(kserdes_release_reset, sc);
+
+	if (!poll)
+		goto done;
+
+	/* Check Lane OK */
+	if (sc->phy_type == KSERDES_PHY_PCIE)
+		ret = kserdes_deassert_reset_poll_pcie(sc);
+	else
+		ret = kserdes_deassert_reset_poll_others(sc);
+
+done:
+	return ret;
+}
+
+static inline void kserdes_lane_disable(struct kserdes_config *sc, u32 lane)
+{
+	FINSR(sc->regs, LANE_CTRL_STS_REG(lane), 31, 29, 0x4);
+	FINSR(sc->regs, LANE_CTRL_STS_REG(lane), 15, 13, 0x4);
+}
+
+static inline void _kserdes_lane_enable(void __iomem *sregs, u32 lane)
+{
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 31, 29, 0x7);
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 15, 13, 0x7);
+}
+
+/* Caller should make sure sgmii cannot be fullrate */
+static inline int _kserdes_set_lane_ctrl_rate(
+	void __iomem			*sregs,
+	u32				lane,
+	enum KSERDES_LANE_CTRL_RATE	lane_ctrl_rate)
+{
+	u32 rate_mode;
+
+	if (lane_ctrl_rate == KSERDES_FULL_RATE)
+		rate_mode = 0x4;
+	else if (lane_ctrl_rate == KSERDES_QUARTER_RATE)
+		rate_mode = 0x6;
+	else if (lane_ctrl_rate == KSERDES_HALF_RATE)
+		rate_mode = 0x5;
+	else
+		return -EINVAL;
+
+	/* Tx */
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 28, 26, rate_mode);
+	/* Rx */
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 12, 10, rate_mode);
+	return 0;
+}
+
+static inline void _kserdes_set_lane_loopback(
+	void __iomem			*sregs,
+	u32				lane,
+	enum KSERDES_LINK_RATE		link_rate)
+{
+	if (link_rate == KSERDES_LINK_RATE_10P3125G) {
+		FINSR(sregs, LANEX_REG(lane, 0x0), 7, 0, 0x4);
+		FINSR(sregs, LANEX_REG(lane, 0x4), 2, 1, 0x3);
+	} else {
+		FINSR(sregs, LANEX_REG(lane, 0x0), 31, 24, 0x40);
+	}
+}
+
+static void kserdes_set_lane_rate(struct kserdes_config *sc, u32 lane)
+{
+	int ret;
+
+	ret = _kserdes_set_lane_ctrl_rate(sc->regs, lane,
+					  sc->lane[lane].ctrl_rate);
+	if (ret) {
+		dev_err(sc->dev, "set_lane_rate FAILED: lane = %d err = %d\n",
+			lane, ret);
+		return;
+	}
+
+	/* disable attenuation auto scale */
+	FINSR(sc->regs, LANEX_REG(lane, 0x30), 11, 11, 0x1);
+	FINSR(sc->regs, LANEX_REG(lane, 0x30), 13, 12, 0x0);
+
+	/* set NES bit if loopback enabled */
+	if (sc->lane[lane].loopback)
+		_kserdes_set_lane_loopback(sc->regs, lane, sc->link_rate);
+
+	_kserdes_lane_enable(sc->regs, lane);
+}
+
+static inline void _kserdes_set_wait_after(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 17, 16, 0x3);
+}
+
+static inline void _kserdes_clear_wait_after(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 17, 16, 0);
+}
+
+static inline void _kserdes_pll_enable(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 31, 29, 0x7);
+}
+
+static inline void _kserdes_pll2_enable(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 27, 25, 0x7);
+}
+
+static inline void _kserdes_pll_disable(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 31, 29, 0x4);
+}
+
+static inline void _kserdes_pll2_disable(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 27, 25, 0x4);
+}
+
+static inline u32 _kserdes_get_pll_status(void __iomem *sregs)
+{
+	return FEXTR(kserdes_readl(sregs, PLL_CTRL_REG), 28, 28);
+}
+
+static inline u32 _kserdes_get_pll2_status(void __iomem *sregs)
+{
+	return FEXTR(kserdes_readl(sregs, PLL_CTRL_REG), 24, 24);
+}
+
+static inline void kserdes_lane_enable_loopback(void __iomem *serdes, u32 lane)
+{
+	FINSR(serdes, LANEX_REG(lane, 0), 31, 24, 0x40);
+}
+
+static inline u32 _kserdes_get_lane_status(
+		void __iomem		*sregs,
+		u32			lane,
+		enum KSERDES_PHY_TYPE	phy_type)
+{
+	if (phy_type == KSERDES_PHY_PCIE) {
+		return FEXTR(kserdes_readl(sregs, PLL_CTRL_REG), lane, lane);
+	} else if (phy_type == KSERDES_PHY_XGE) {
+		return FEXTR(kserdes_readl(sregs, CML_REG(0x1f8)),
+			     (29 + lane), (29 + lane));
+	} else {
+		return FEXTR(kserdes_readl(sregs, PLL_CTRL_REG),
+			     (8 + lane), (8 + lane));
+	}
+}
+
+static u32 kserdes_get_pll_lanes_status(struct kserdes_config *sc)
+{
+	u32 val, i;
+
+	/* Check PLL OK Status Bit */
+	val = _kserdes_get_pll_status(sc->regs);
+	if (!val) {
+		/* pll is not ready */
+		goto done;
+	}
+
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		val = _kserdes_get_pll2_status(sc->regs);
+		if (!val)
+			goto done;
+	}
+
+	/* Check Lane OK Status Bits */
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		val &= _kserdes_get_lane_status(sc->regs, i, sc->phy_type);
+	}
+
+done:
+	/* if any of the status is 0, this is 0
+	 * i.e. serdes status is not good
+	 */
+	return val;
+}
+
+int kserdes_get_status(struct kserdes_config *sc)
+{
+	unsigned long timeout;
+
+	/* is 500 msec a good number? */
+	timeout = jiffies + msecs_to_jiffies(500);
+	do {
+		if (kserdes_get_pll_lanes_status(sc))
+			break;
+
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+
+		cpu_relax();
+	} while (true);
+
+	return 0;
+}
+
+static inline u32 _kserdes_get_tx_termination(
+		void __iomem		*sregs,
+		enum KSERDES_PHY_TYPE	phy_type,
+		u32			lane)
+{
+	return (_kserdes_read_select_tbus(sregs, lane + 1,
+					  ((phy_type == KSERDES_PHY_XGE) ?
+					  0x1a : 0x1b)) & 0xff);
+}
+
+static void kserdes_set_tx_terminations(struct kserdes_config *sc, u32 term)
+{
+	u32 i;
+
+	for (i = 0; i < sc->lanes; i++) {
+		FINSR(sc->regs, LANEX_REG(i, 0x7c), 31, 24, term);
+		/* set termination override */
+		FINSR(sc->regs, LANEX_REG(i, 0x7c), 20, 20, 0x1);
+	}
+}
+
+/* lane is 0-based */
+static void
+_kserdes_get_cmp_tap_offsets_xge(void __iomem *sregs, u32 lane, u32 cmp,
+				 struct kserdes_comparator_tap_offsets *ofs)
+{
+	/* set comparator number */
+	FINSR(sregs, CML_REG(0x8c), 23, 21, cmp);
+
+	/* read offsets */
+	FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((lane + 2) << 8) + 0x11);
+	ofs->cmp = (_kserdes_read_tbus_val(sregs) & 0x0ff0) >> 4;
+
+	FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((lane + 2) << 8) + 0x11);
+	ofs->tap1 = (_kserdes_read_tbus_val(sregs) & 0x000f) << 3;
+
+	FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((lane + 2) << 8) + 0x12);
+	ofs->tap1 |= (_kserdes_read_tbus_val(sregs) & 0x0e00) >> 9;
+	ofs->tap2  = (_kserdes_read_tbus_val(sregs) & 0x01f8) >> 3;
+	ofs->tap3  = (_kserdes_read_tbus_val(sregs) & 0x0007) << 3;
+
+	FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((lane + 2) << 8) + 0x13);
+	ofs->tap3 |= (_kserdes_read_tbus_val(sregs) & 0x0e00) >> 9;
+	ofs->tap4  = (_kserdes_read_tbus_val(sregs) & 0x01f8) >> 3;
+	ofs->tap5  = (_kserdes_read_tbus_val(sregs) & 0x0007) << 3;
+
+	FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((lane + 2) << 8) + 0x14);
+	ofs->tap5 |= (_kserdes_read_tbus_val(sregs) & 0x0e00) >> 9;
+}
+
+static void kserdes_add_offsets_xge(struct kserdes_config *sc,
+				    struct kserdes_offsets *sofs)
+{
+	struct kserdes_comparator_tap_offsets *ctofs;
+	struct kserdes_comparator_tap_offsets sample;
+	struct kserdes_lane_offsets *lofs;
+	u32 lane, cmp;
+
+	for (lane = 0; lane < sc->lanes; lane++) {
+		lofs = &sofs->lane_ofs[lane];
+		/* yes cmp starts from 1 */
+		for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+			ctofs = &lofs->ct_ofs[cmp];
+
+			_kserdes_get_cmp_tap_offsets_xge(sc->regs, lane,
+							 cmp, &sample);
+
+			ctofs->cmp  += sample.cmp;
+			ctofs->tap1 += sample.tap1;
+			ctofs->tap2 += sample.tap2;
+			ctofs->tap3 += sample.tap3;
+			ctofs->tap4 += sample.tap4;
+			ctofs->tap5 += sample.tap5;
+		}
+	}
+}
+
+/* lane is 0-based */
+static void
+kserdes_get_cmp_tap_offsets_non_xge(void __iomem *sregs, u32 lane, u32 cmp,
+				    struct kserdes_comparator_tap_offsets *ofs)
+{
+	/* set comparator number */
+	FINSR(sregs, CML_REG(0x8c), 23, 21, cmp);
+
+	/* read offsets */
+	FINSR(sregs, CMU0_REG(0x8), 31, 24, ((lane + 1) << 5) + 0x12);
+	ofs->cmp = (_kserdes_read_tbus_val(sregs) & 0x0ff0) >> 4;
+}
+
+static void kserdes_add_offsets_non_xge(struct kserdes_config *sc,
+					struct kserdes_offsets *sofs)
+{
+	struct kserdes_comparator_tap_offsets *ctofs;
+	struct kserdes_comparator_tap_offsets sample;
+	struct kserdes_lane_offsets *lofs;
+	u32 lane, cmp;
+
+	for (lane = 0; lane < sc->lanes; lane++) {
+		lofs = &sofs->lane_ofs[lane];
+		/* yes cmp starts from 1 */
+		for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+			ctofs = &lofs->ct_ofs[cmp];
+
+			kserdes_get_cmp_tap_offsets_non_xge(sc->regs, lane,
+							    cmp, &sample);
+
+			ctofs->cmp  += sample.cmp;
+		}
+	}
+}
+
+static void kserdes_get_average_offsets(struct kserdes_config *sc, u32 samples,
+					struct kserdes_offsets *sofs)
+{
+	struct kserdes_comparator_tap_offsets *ctofs;
+	struct kserdes_lane_offsets *lofs;
+	u32 i, lane, cmp;
+	int ret;
+
+	memset(sofs, 0, sizeof(*sofs));
+
+	/* get the total of each offset for specified number of samples */
+	for (i = 0; i < samples; i++) {
+		kserdes_assert_reset(sc);
+		ret = kserdes_deassert_reset(sc, 1);
+		if (ret) {
+			dev_err(sc->dev,
+				"kserdes_get_average_offsets: reset failed %d\n",
+				ret);
+			return;
+		}
+
+		if (sc->phy_type == KSERDES_PHY_XGE)
+			kserdes_add_offsets_xge(sc, sofs);
+		else
+			kserdes_add_offsets_non_xge(sc, sofs);
+	}
+
+	/* take the average */
+	for (lane = 0; lane < sc->lanes; lane++) {
+		lofs = &sofs->lane_ofs[lane];
+		/* yes cmp starts from 1 */
+		for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+			ctofs = &lofs->ct_ofs[cmp];
+			if (sc->phy_type == KSERDES_PHY_XGE) {
+				ctofs->cmp  /= samples;
+				ctofs->tap1 /= samples;
+				ctofs->tap2 /= samples;
+				ctofs->tap3 /= samples;
+				ctofs->tap4 /= samples;
+				ctofs->tap5 /= samples;
+			} else {
+				ctofs->cmp  /= samples;
+			}
+		}
+	}
+}
+
+static void
+_kserdes_override_cmp_tap_offsets(void __iomem *sregs, u32 lane, u32 cmp,
+				  struct kserdes_comparator_tap_offsets *ofs)
+{
+	/* set dfe_shadow_lane_sel */
+	FINSR(sregs, CML_REG(0xf0), 27, 26, (lane + 1));
+
+	/* set cmp_offset_ovr_en to 1 */
+	FINSR(sregs, CML_REG(0x98), 24, 24, 0x1);
+
+	/* set rxeq_ovr_en to 0x1 */
+	FINSR(sregs, LANEX_REG(lane, 0x2c), 2, 2, 0x1);
+
+	/* set rxeq_dfe_cmp_sel_ovr to comp_no */
+	FINSR(sregs, LANEX_REG(lane, 0x30), 7, 5, cmp);
+
+	/* set dfe_tap_ovr_en to 1 */
+	FINSR(sregs, LANEX_REG(lane, 0x5c), 31, 31, 0x1);
+
+	/* set cmp offset override */
+	FINSR(sregs, CML_REG(0x9c), 7, 0, ofs->cmp);
+	/* set tap offset overrides */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 30, 24, ofs->tap1);
+	FINSR(sregs, LANEX_REG(lane, 0x5c),  5,  0, ofs->tap2);
+	FINSR(sregs, LANEX_REG(lane, 0x5c), 13,  8, ofs->tap3);
+	FINSR(sregs, LANEX_REG(lane, 0x5c), 21, 16, ofs->tap4);
+	FINSR(sregs, LANEX_REG(lane, 0x5c), 29, 24, ofs->tap5);
+
+	/* set rxeq_ovr_latch_o = 0x1 */
+	FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x1);
+	/* set rxeq_ovr_latch_o = 0x0 */
+	FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x0);
+
+	/* set cmp_offset_ovr_en to 0 */
+	FINSR(sregs, CML_REG(0x98), 24, 24, 0x0);
+	/* set rxeq_ovr_en to 0x0 */
+	FINSR(sregs, LANEX_REG(lane, 0x2c), 2, 2, 0x0);
+	/* set dfe_tap_ovr_en to 0 */
+	FINSR(sregs, LANEX_REG(lane, 0x5c), 31, 31, 0x0);
+}
+
+static inline void
+_kserdes_override_cmp_offset_cdfe(void __iomem *sregs, u32 lane,
+				  u32 cmp, u32 cmp_offset)
+{
+	/* enable comparator offset calibrate */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 18, 18, 0x1);
+
+	/* set gcfsm sel override to comparator */
+	FINSR(sregs, LANEX_REG(lane, 0x4c), 5, 2, (0x1 << (cmp - 1)));
+	/* set comparator offset */
+	FINSR(sregs, LANEX_REG(lane, 0x48), 24, 17, cmp_offset);
+	/* latch in value */
+	FINSR(sregs, LANEX_REG(lane, 0x48), 29, 29, 0x1);
+	FINSR(sregs, LANEX_REG(lane, 0x48), 29, 29, 0x0);
+
+	/* disable comparator offset calibrate */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 18, 18, 0x0);
+}
+
+static inline void
+_kserdes_override_tap_offset_cdfe(void __iomem *sregs, u32 lane,
+				  u32 tap, u32 width, u32 tap_offset)
+{
+	/* enable tap */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 23, 19, BIT(tap - 1));
+	/* set tap offset */
+	FINSR(sregs, LANEX_REG(lane, 0x48), 17 + (width - 1), 17, tap_offset);
+	/* latch in value */
+	FINSR(sregs, LANEX_REG(lane, 0x48), 29, 29, 0x1);
+	FINSR(sregs, LANEX_REG(lane, 0x48), 29, 29, 0x0);
+}
+
+static void _kserdes_override_cmp_tap_offsets_cdfe(
+	void __iomem				*sregs,
+	u32					lane,
+	u32					cmp,
+	struct kserdes_comparator_tap_offsets	*ofs)
+{
+	/* enable overrides */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 16, 16, 0x1);
+	FINSR(sregs, LANEX_REG(lane, 0x48), 16, 16, 0x1);
+
+	_kserdes_override_cmp_offset_cdfe(sregs, lane, cmp, ofs->cmp);
+
+	/* enable tap offset calibrate */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 17, 17, 0x1);
+
+	/* set tap offsets */
+	_kserdes_override_tap_offset_cdfe(sregs, lane, 1, 7, ofs->tap1);
+	_kserdes_override_tap_offset_cdfe(sregs, lane, 2, 6, ofs->tap2);
+	_kserdes_override_tap_offset_cdfe(sregs, lane, 3, 6, ofs->tap3);
+	_kserdes_override_tap_offset_cdfe(sregs, lane, 4, 6, ofs->tap4);
+	_kserdes_override_tap_offset_cdfe(sregs, lane, 5, 6, ofs->tap5);
+
+	/* disable overrides */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 16, 16, 0x0);
+	FINSR(sregs, LANEX_REG(lane, 0x48), 16, 16, 0x0);
+	FINSR(sregs, LANEX_REG(lane, 0x58), 18, 18, 0x0);
+	FINSR(sregs, LANEX_REG(lane, 0x58), 17, 17, 0x0);
+}
+
+static void kserdes_set_offsets_xge(struct kserdes_config *sc,
+				    struct kserdes_offsets *sofs)
+{
+	struct kserdes_comparator_tap_offsets *ctofs;
+	struct kserdes_lane_offsets *lofs;
+	u32 lane, cmp;
+
+	for (lane = 0; lane < sc->lanes; lane++) {
+		lofs = &sofs->lane_ofs[lane];
+		for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+			ctofs = &lofs->ct_ofs[cmp];
+			_kserdes_override_cmp_tap_offsets(sc->regs, lane,
+							  cmp, ctofs);
+			_kserdes_override_cmp_tap_offsets_cdfe(sc->regs, lane,
+							       cmp, ctofs);
+		}
+	}
+}
+
+static void kserdes_set_offsets_non_xge(struct kserdes_config *sc,
+					struct kserdes_offsets *sofs)
+{
+	struct kserdes_comparator_tap_offsets *ctofs;
+	struct kserdes_lane_offsets *lofs;
+	u32 lane, cmp;
+
+	for (lane = 0; lane < sc->lanes; lane++) {
+		lofs = &sofs->lane_ofs[lane];
+		for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+			ctofs = &lofs->ct_ofs[cmp];
+			_kserdes_override_cmp_tap_offsets(sc->regs, lane,
+							  cmp, ctofs);
+		}
+	}
+}
+
+static void kserdes_set_offsets(struct kserdes_config *sc,
+				struct kserdes_offsets *sofs)
+{
+	if (sc->phy_type == KSERDES_PHY_XGE)
+		kserdes_set_offsets_xge(sc, sofs);
+	else
+		kserdes_set_offsets_non_xge(sc, sofs);
+}
+
+static void kserdes_dfe_offset_calibration(struct kserdes_config *sc,
+					   struct kserdes_offsets *sofs)
+{
+	for_each_enable_lane(kserdes_force_signal_detect_low, sc);
+	usleep_range(10, 20);
+
+	/* offset compensation patch */
+	kserdes_get_average_offsets(sc, DFE_OFFSET_SAMPLES, sofs);
+	kserdes_set_offsets(sc, sofs);
+	usleep_range(10, 20);
+
+	/* re-acquire signal detect */
+	for_each_lane(kserdes_force_signal_detect_high, sc);
+	usleep_range(10, 20);
+}
+
+static void kserdes_override_tap_offsets(struct kserdes_config *sc, u32 lane)
+{
+	u32 tap1val, tap2val, tap3val, tap4val, tap5val;
+	void __iomem *sregs = sc->regs;
+	u32 cmp, tap1_ofs;
+
+	for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+		/* adjust taps only for center comparators of
+		 * of conparator 1 and 3
+		 */
+		if (!(cmp & 0x1))
+			continue;
+
+		/* set comparator number */
+		FINSR(sregs, CML_REG(0x8c), 23, 21, cmp);
+
+		/* read offsets */
+		FINSR(sregs, CMU0_REG(0x8), 31, 24, ((lane + 1) << 5) + 0x12);
+		tap1_ofs = (_kserdes_read_tbus_val(sregs) & 0x000f) << 3;
+
+		FINSR(sregs, CMU0_REG(0x8), 31, 24, ((lane + 1) << 5) + 0x13);
+		tap1_ofs |= (_kserdes_read_tbus_val(sregs) & 0x0e00) >> 9;
+
+		tap1val = tap1_ofs - 14;
+		tap2val = 31;
+		tap3val = 31;
+		tap4val = 31;
+		tap5val = 31;
+
+		/* set dfe_shadow_lane_sel */
+		FINSR(sregs, CML_REG(0xf0), 27, 26, lane + 1);
+		/* Set rxeq_ovr_en to 0x1 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 2, 2, 0x1);
+		/* set rxeq_dfe_cmp_sel_ovr to comp_no */
+		FINSR(sregs, LANEX_REG(lane, 0x30), 7, 5, cmp);
+		/* set dfe_tap_ovr_en to 1 */
+		FINSR(sregs, LANEX_REG(lane, 0x5c), 31, 31, 0x1);
+
+		/* set tap overrides */
+		FINSR(sregs, LANEX_REG(lane, 0x58), 30, 24, tap1val);
+		FINSR(sregs, LANEX_REG(lane, 0x5c),  6,  0, tap2val);
+		FINSR(sregs, LANEX_REG(lane, 0x5c), 13,  8, tap3val);
+		FINSR(sregs, LANEX_REG(lane, 0x5c), 21, 16, tap4val);
+		FINSR(sregs, LANEX_REG(lane, 0x5c), 29, 24, tap5val);
+
+		/* set rxeq_ovr_latch_o = 0x1 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x1);
+		/* set rxeq_ovr_latch_o = 0x0 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x0);
+
+		/* set rxeq_ovr_en to 0 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 2, 2, 0x0);
+		/* set dfe_tap_ovr_en to 0 */
+		FINSR(sregs, LANEX_REG(lane, 0x5c), 31, 31, 0x0);
+
+		/* This part of code will latch in offsets to
+		 * tap adaptation logic so that if adaptation
+		 * occurs, it will pick these offsets
+		 */
+		/* enable overrides */
+		FINSR(sregs, LANEX_REG(lane, 0x58), 16, 16, 0x1);
+		FINSR(sregs, LANEX_REG(lane, 0x48), 16, 16, 0x1);
+
+		/* set gcfsm_cmp_sel to comp_no */
+		FINSR(sregs, LANEX_REG(lane, 0x4c), 5, 2, (0x1 << (cmp - 1)));
+		/* enable tap offset calibrate */
+		FINSR(sregs, LANEX_REG(lane, 0x58), 17, 17, 0x1);
+
+		/* enable taps */
+		_kserdes_override_tap_offset_cdfe(sregs, lane, 1, 7, tap1val);
+		_kserdes_override_tap_offset_cdfe(sregs, lane, 2, 6, tap2val);
+		_kserdes_override_tap_offset_cdfe(sregs, lane, 3, 6, tap3val);
+		_kserdes_override_tap_offset_cdfe(sregs, lane, 4, 6, tap4val);
+		_kserdes_override_tap_offset_cdfe(sregs, lane, 5, 6, tap5val);
+
+		/* Disable overrides */
+		FINSR(sregs, LANEX_REG(lane, 0x58), 16, 16, 0x0);
+		FINSR(sregs, LANEX_REG(lane, 0x48), 16, 16, 0x0);
+		FINSR(sregs, LANEX_REG(lane, 0x58), 17, 17, 0x0);
+	}
+}
+
+static int kserdes_wait_lane_rx_valid(struct kserdes_config *sc, u32 lane)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(500);
+	u32 status;
+
+	do {
+		status = _kserdes_read_select_tbus(sc->regs, lane + 1, 0x02);
+
+		if (status & 0x20)
+			return 0;
+
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+
+		cpu_relax();
+	} while (true);
+}
+
+static int kserdes_att_boost_phya_macro_patch(struct kserdes_config *sc)
+{
+	u32 i, att_read[KSERDES_MAX_LANES], att_start[KSERDES_MAX_LANES];
+	int ret;
+
+	/* First save a copy of initial att start value */
+	for (i = 0; i < sc->lanes; i++) {
+		att_start[i] = kserdes_readl(sc->regs, LANEX_REG(i, 0x8c));
+		att_start[i] = (att_start[i] >> 8) & 0xf;
+	}
+	/* Get att and fix this as start value.  Turn off att adaptation and
+	 * do boost readaptation
+	 */
+	for (i = 0; i < sc->lanes; i++) {
+		att_read[i] = _kserdes_read_select_tbus(
+					sc->regs, i + 1,
+					(sc->phy_type == KSERDES_PHY_XGE) ?
+					0x10 : 0x11);
+		att_read[i] = (att_read[i] >> 4) & 0xf;
+	}
+	for (i = 0; i < sc->lanes; i++) {
+		/* att start */
+		FINSR(sc->regs, LANEX_REG(i, 0x8c), 11, 8, att_read[i]);
+	}
+	/* clear att init calibration */
+	FINSR(sc->regs, CML_REG(0x84), 0, 0, 0x0);
+	/* clear att re-calibration */
+	FINSR(sc->regs, CML_REG(0x8c), 24, 24, 0x0);
+
+	/* force calibration on all lanes */
+	/* set att continuous recal */
+	FINSR(sc->regs, CML_REG(0x98), 7, 7, 0x1);
+	/* clear att continuous recal */
+	FINSR(sc->regs, CML_REG(0x98), 7, 7, 0x0);
+	usleep_range(300, 400);
+
+	/* check rx valid */
+	for_each_enable_lane_return(kserdes_wait_lane_rx_valid, sc, ret);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_wait_lane_rx_valid FAILED %d\n", ret);
+		return ret;
+	}
+
+	/* write back initial att start value */
+	for (i = 0; i < sc->lanes; i++)
+		FINSR(sc->regs, LANEX_REG(i, 0x8c), 11, 8, att_start[i]);
+
+	/* turn att adaptation back on */
+	FINSR(sc->regs, CML_REG(0x84),  0,  0, 0x1);
+	FINSR(sc->regs, CML_REG(0x8c), 24, 24, 0x1);
+
+	return 0;
+}
+
+static int kserdes_att_boost_phya_lane_patch(struct kserdes_config *sc,
+					     u32 lane)
+{
+	u32 boost_read;
+	int ret;
+
+	/* check lane rx valid */
+	ret = kserdes_wait_lane_rx_valid(sc, lane);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_wait_lane_rx_valid FAILED %d\n", ret);
+		return ret;
+	}
+
+	/* check boost value */
+	boost_read = _kserdes_read_select_tbus(
+				sc->regs, lane + 1,
+				(sc->phy_type == KSERDES_PHY_XGE) ?
+				0x10 : 0x11);
+	boost_read = (boost_read >> 8) & 0xf;
+
+	/* increment boost by 1 if it's 0 */
+	if (!boost_read) {
+		/* Set rxeq_ovr_en to 1 */
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c),  2,  2, 0x1);
+		/* set rxeq_ovr_load_en for boost only */
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c), 18, 12, 0x2);
+		/* set rxeq_ovr_load for a value of 1 */
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c),  9,  3, 0x1);
+		/* latch in new boost value */
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c), 10, 10, 0x1);
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c), 10, 10, 0x0);
+		/* reset previous registers */
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c),  2,  2, 0x0);
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c), 18, 12, 0x0);
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c),  9,  3, 0x0);
+	}
+	return 0;
+}
+
+static inline void kserdes_att_boost_phya_patch(struct kserdes_config *sc)
+{
+	kserdes_att_boost_phya_macro_patch(sc);
+
+	for_each_enable_lane(kserdes_att_boost_phya_lane_patch, sc);
+}
+
+static void kserdes_att_boost_phyb_lane_patch(struct kserdes_config *sc,
+					      u32 lane)
+{
+	u32 tbus_ofs, rxeq_init_reg_ofs, rxeq_ln_reg_ofs, rxeq_ln_force_bit;
+	void __iomem *sregs = sc->regs;
+	u32 att_start, att_read, boost_read;
+	int ret;
+
+	/* some setups */
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		tbus_ofs = 0x10;
+		rxeq_init_reg_ofs = 0x9c;
+		rxeq_ln_reg_ofs = 0x98;
+		rxeq_ln_force_bit = 14;
+	} else {
+		tbus_ofs = 0x11;
+		rxeq_init_reg_ofs = 0x84;
+		rxeq_ln_reg_ofs = 0xac;
+		rxeq_ln_force_bit = 11;
+	}
+
+	/* First save a copy of initial att start value */
+	att_start = kserdes_readl(sregs, LANEX_REG(lane, 0x8c));
+	att_start = (att_start >> 8) & 0xf;
+
+	/* Get att and fix this as start value.  Turn off att adaptation and
+	 * do boost readaptation
+	 */
+	att_read = _kserdes_read_select_tbus(sregs, lane + 1, tbus_ofs);
+	att_read = (att_read >> 4) & 0xf;
+
+	/* att start */
+	FINSR(sregs, LANEX_REG(lane, 0x8c), 11, 8, att_read);
+	/* clear att init calibration */
+	FINSR(sregs, LANEX_REG(lane, rxeq_init_reg_ofs), 0, 0, 0x0);
+	/* clear att re-calibration */
+	FINSR(sregs, CML_REG(0x8c), 24, 24, 0x0);
+
+	/* force calibration */
+	FINSR(sregs, LANEX_REG(lane, rxeq_ln_reg_ofs),
+	      rxeq_ln_force_bit, rxeq_ln_force_bit, 0x1);
+	FINSR(sregs, LANEX_REG(lane, rxeq_ln_reg_ofs),
+	      rxeq_ln_force_bit, rxeq_ln_force_bit, 0x0);
+
+	/* check lane rx valid */
+	ret = kserdes_wait_lane_rx_valid(sc, lane);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_wait_lane_rx_valid %d FAILED: %d\n",
+			lane, ret);
+	}
+	usleep_range(300, 400);
+
+	/* check boost value */
+	boost_read = _kserdes_read_select_tbus(sregs, lane + 1, tbus_ofs);
+	boost_read = (boost_read >> 8) & 0xf;
+
+	/* increment boost by 1 if it's 0 */
+	if (!boost_read) {
+		/* Set rxeq_ovr_en to 1 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c),  2,  2, 0x1);
+		/* set rxeq_ovr_load_en for boost only */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 18, 12, 0x2);
+		/* set rxeq_ovr_load for a value of 1 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c),  9,  3, 0x1);
+		/* latch in new boost value */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x1);
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x0);
+		/* reset previous registers */
+		FINSR(sregs, LANEX_REG(lane, 0x2c),  2,  2, 0x0);
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 18, 12, 0x0);
+		FINSR(sregs, LANEX_REG(lane, 0x2c),  9,  3, 0x0);
+	}
+
+	/* write back initial att start value */
+	FINSR(sregs, LANEX_REG(lane, 0x8c), 11, 8, att_start);
+	/* turn att adaptation back on */
+	FINSR(sregs, LANEX_REG(lane, rxeq_init_reg_ofs), 0, 0, 0x1);
+	FINSR(sregs, CML_REG(0x8c), 24, 24, 0x1);
+}
+
+static inline void kserdes_att_boost_phyb_patch(struct kserdes_config *sc,
+						u32 lane)
+{
+	kserdes_att_boost_phyb_lane_patch(sc, lane);
+}
+
+static void kserdes_att_boost_phy_patch(struct kserdes_config *sc)
+{
+	if (sc->phy_type != KSERDES_PHY_XGE)
+		kserdes_att_boost_phya_patch(sc);
+	else
+		for_each_lane(kserdes_att_boost_phyb_patch, sc);
+}
+
+int kserdes_sgmii_lanes_enable(struct kserdes_config *sc)
+{
+	int ret, i;
+	u32 val, lanes_enable = 0;
+
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		lanes_enable |= (1 << i);
+	}
+
+	/* configure Tap 1 if PHY-A and link rate greater than 8Gbaud */
+	if (sc->link_rate >= KSERDES_LINK_RATE_9P8304G)
+		kserdes_tap1_patch(sc);
+
+	/* disable transmitter on all lanes to prevent
+	 * receiver from adapting
+	 */
+	for_each_lane(kserdes_set_tx_idle, sc);
+
+	/* apply patch for link rates greater than 8Gbaud */
+	kserdes_phy_patch(sc);
+
+	/* write boost training pattern for Hyperlink functional mode */
+	if (sc->phy_type == KSERDES_PHY_HYPERLINK)
+		_kserdes_set_training_pattern(sc->regs);
+
+	/* assert serdes reset */
+	kserdes_assert_reset(sc);
+
+	/* apply the TX and RX FIR coefficients to the lanes */
+	for_each_enable_lane(kserdes_set_tx_rx_fir_coeff, sc);
+
+	/* force Signal Detect Low. This resets the CDR,
+	 * Attenuation and Boost circuitry
+	 */
+	for_each_enable_lane(kserdes_force_signal_detect_low, sc);
+
+	ret = kserdes_deassert_reset(sc, 0);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_deassert_reset FAILED %d\n", ret);
+		return ret;
+	}
+
+	/* allow signal detect enable */
+	for_each_enable_lane(kserdes_set_lane_rate, sc);
+
+	_kserdes_pll_enable(sc->regs);
+
+	ret = kserdes_get_status(sc);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_get_status FAILED %d\n", ret);
+		return ret;
+	}
+
+	/* get tx termination on lane 0 */
+	val = _kserdes_get_tx_termination(sc->regs, sc->phy_type, 0);
+
+	/* apply tx termination to all lanes */
+	kserdes_set_tx_terminations(sc, val);
+
+	if (sc->link_rate >= KSERDES_LINK_RATE_9P8304G) {
+		/* manually adjust Tap 1 value for phy-a > 8GBaud */
+		for_each_enable_lane(kserdes_override_tap_offsets, sc);
+	}
+
+	/* We are always in FUNCTIONAL mode, so we always
+	 * continue to the following.
+	 */
+	/* enable transmitter on all lanes */
+	for_each_enable_lane(kserdes_clr_tx_idle, sc);
+
+	/* allow Signal Detect Enable */
+	for_each_enable_lane(kserdes_force_signal_detect_high, sc);
+
+	/* Wait for RX Valid on all lanes */
+	for_each_enable_lane_return(kserdes_wait_lane_rx_valid, sc, ret);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_wait_lane_rx_valid FAILED %d\n", ret);
+		return ret;
+	}
+
+	/* Apply Attenuation and Boost Patch if rx force
+	 * flag is set
+	 */
+	if (!sc->rx_force_enable)
+		kserdes_att_boost_phy_patch(sc);
+
+	/* If needed, check for errors or see if DLPF is
+	 * railing and toggle signal detect
+	 */
+	/* CSL_Serdes_CDR_Reset(); */
+
+	/* Enable MAC RX to allow MAC to take control */
+	_kserdes_clear_wait_after(sc->regs);
+
+	return lanes_enable;
+}
+
+static int kserdes_sgmii_init(struct kserdes_config *sc)
+{
+	return kserdes_load_init_fw(sc, ks2_gbe_serdes_firmwares,
+				    ARRAY_SIZE(ks2_gbe_serdes_firmwares));
+}
+
+static inline void _kserdes_set_link_loss_wait(void __iomem *sregs,
+					       u32 link_loss_wait)
+{
+	kserdes_writel(sregs, LINK_LOSS_WAIT_REG, link_loss_wait);
+}
+
+static inline void _kserdes_reset(void __iomem *sregs)
+{
+	/* Toggle POR_EN bit */
+	FINSR(sregs, CPU_CTRL_REG, 29, 29, 0x1);
+	usleep_range(10, 20);
+	FINSR(sregs, CPU_CTRL_REG, 29, 29, 0x0);
+	usleep_range(10, 20);
+}
+
+static inline void kserdes_xge_pll_enable(struct kserdes_config *sc)
+{
+	/* phyb reset clear */
+	if (!sc->firmware)
+		FINSR(sc->regs, CML_REG(0), 7, 0, 0x1f);
+
+	if (sc->link_rate == KSERDES_LINK_RATE_10P3125G) {
+		_kserdes_pll_enable(sc->regs);
+		_kserdes_pll2_enable(sc->regs);
+	} else if (sc->link_rate == KSERDES_LINK_RATE_1P25G) {
+		kserdes_writel(sc->regs, PLL_CTRL_REG, 0xe0000000);
+	}
+}
+
+static inline void _kserdes_xge_enable_pcs(void __iomem *sregs, u32 lane)
+{
+	/* set bus-width to 16 bit mode */
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 23, 21, 0x7);
+	FINSR(sregs, LANE_CTRL_STS_REG(lane),  5,  3, 0x7);
+
+	/* enable PCS overlay and lane select 10GKR */
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 16, 16, 0x1);
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 19, 19, 0x1);
+}
+
+static inline void kserdes_xge_lane_enable(struct kserdes_config *sc, u32 lane)
+{
+	u32 lane_ctrl_rate = sc->lane[lane].ctrl_rate;
+
+	/* Set Lane Control Rate */
+	if (sc->link_rate == KSERDES_LINK_RATE_10P3125G)
+		_kserdes_set_lane_ctrl_rate(sc->regs, lane, lane_ctrl_rate);
+	else if (sc->link_rate == KSERDES_LINK_RATE_1P25G)
+		kserdes_writel(sc->regs, LANE_CTRL_STS_REG(lane), 0xf800f8c0);
+
+	_kserdes_xge_enable_pcs(sc->regs, lane);
+
+	_kserdes_lane_enable(sc->regs, lane);
+
+	if (sc->lane[lane].loopback)
+		_kserdes_set_lane_loopback(sc->regs, lane, sc->link_rate);
+}
+
+static inline void _kserdes_enable_xgmii_port(struct regmap *peripheral_regmap,
+					      u32 port)
+{
+	regmap_update_bits(peripheral_regmap, XGE_CTRL_OFFSET,
+			   GENMASK(port, port), BIT(port));
+}
+
+static inline void _kserdes_reset_cdr(void __iomem *sregs, int lane)
+{
+	/* toggle signal detect */
+	_kserdes_force_signal_detect_low(sregs, lane);
+	mdelay(1);
+	_kserdes_force_signal_detect_high(sregs, lane);
+}
+
+/* Call every 10 ms */
+static int
+_kserdes_check_link_status(struct device *dev, void __iomem *sregs,
+			   struct regmap *pcsr_regmap, u32 lanes,
+			   u32 lanes_enable, u32 *current_state, u32 *lane_down)
+{
+	u32 pcsr_rx_stat, blk_lock, blk_errs;
+	int loss, i, status = 1;
+	int ret;
+
+	for (i = 0; i < lanes; i++) {
+		if (!(lanes_enable & (1 << i)))
+			continue;
+
+		/* Rx Signal Loss bit in serdes lane control and status reg*/
+		loss = (kserdes_readl(sregs, LANE_CTRL_STS_REG(i))) & 0x01;
+
+		/* Block Errors and Block Lock bits in PCSR rx status reg */
+		ret = regmap_read(pcsr_regmap, PCSR_RX_STATUS(i),
+				  &pcsr_rx_stat);
+
+		if (ret)
+			return ret;
+
+		blk_lock = (pcsr_rx_stat >> 30) & 0x1;
+		blk_errs = (pcsr_rx_stat >> 16) & 0x0ff;
+
+		/* If Block error, attempt recovery! */
+		if (blk_errs)
+			blk_lock = 0;
+
+		switch (current_state[i]) {
+		case 0:
+			/* if good link lock the signal detect ON! */
+			if (!loss && blk_lock) {
+				dev_dbg(dev, "XGE PCSR Linked Lane: %d\n", i);
+				FINSR(sregs, LANEX_REG(i, 0x04), 2, 1, 0x3);
+				current_state[i] = 1;
+			} else {
+				/* if no lock, then reset CDR
+				 * by toggling sig detect
+				 */
+				if (!blk_lock) {
+					dev_dbg(dev,
+						"XGE PCSR Recover Lane: %d\n",
+						i);
+
+					_kserdes_reset_cdr(sregs, i);
+				}
+			}
+			break;
+		case 1:
+			if (!blk_lock) {
+				/* Link Lost? */
+				lane_down[i] = 1;
+				current_state[i] = 2;
+			}
+			break;
+		case 2:
+			if (blk_lock)
+				/* Nope just noise */
+				current_state[i] = 1;
+			else {
+				/* Lost the block lock, reset CDR if it is
+				 * not centered and go back to sync state
+				 */
+				_kserdes_reset_cdr(sregs, i);
+
+				current_state[i] = 0;
+			}
+			break;
+		default:
+			dev_info(dev, "XGE: unknown current_state[%d] %d\n",
+				 i, current_state[i]);
+			break;
+		}
+
+		if (blk_errs) {
+			/* Reset the Error counts! */
+			regmap_update_bits(pcsr_regmap, PCSR_RX_CTL(i),
+					   GENMASK(7, 0), 0x19);
+			regmap_update_bits(pcsr_regmap, PCSR_RX_CTL(i),
+					   GENMASK(7, 0), 0x00);
+		}
+
+		status &= (current_state[i] == 1);
+	}
+
+	return status;
+}
+
+static int _kserdes_wait_link_up(struct device *dev, void __iomem *sregs,
+				 struct regmap *pcsr_regmap,
+				 u32 lanes, u32 lanes_enable)
+{
+	u32 current_state[KSERDES_MAX_LANES];
+	int retries = 0, link_up;
+	u32 lane_down[KSERDES_MAX_LANES];
+	int i;
+
+	if (lanes > KSERDES_MAX_LANES)
+		return -EINVAL;
+
+	memset(current_state, 0, sizeof(current_state));
+	memset(lane_down, 0, sizeof(lane_down));
+
+	do {
+		mdelay(10);
+		memset(lane_down, 0, sizeof(lane_down));
+
+		link_up = _kserdes_check_link_status(dev, sregs,
+						     pcsr_regmap, lanes,
+						     lanes_enable,
+						     current_state, lane_down);
+
+		/* if we did not get link up then wait 100ms
+		 * before calling it again
+		 */
+		if (link_up)
+			break;
+
+		for (i = 0; i < lanes; i++) {
+			if ((lanes_enable & (1 << i)) && lane_down[i])
+				dev_dbg(dev,
+					"XGE: detected lane down on lane %d\n",
+					i);
+		}
+
+		if (++retries > 100)
+			return -ETIMEDOUT;
+
+	} while (!link_up);
+
+	dev_info(dev, "XGE: serdes link up: retried %d times\n", retries);
+	return 0;
+}
+
+static int kserdes_xge_lanes_enable(struct kserdes_config *sc)
+{
+	struct kserdes_offsets sofs;
+	int ret, i;
+	u32 lanes_enable = 0;
+
+	if (sc->firmware) {
+		/* firmware started in serdes_init and
+		 * doesn't need lanes enable
+		 */
+		return 0;
+	}
+
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		lanes_enable |= (1 << i);
+	}
+
+	kserdes_phy_patch(sc);
+	kserdes_xge_pll_enable(sc);
+
+	for_each_lane(kserdes_xge_lane_enable, sc);
+
+	ret = kserdes_get_status(sc);
+	if (ret) {
+		dev_err(sc->dev,
+			"kserdes_xge_lanes_enable get status FAILED %d\n", ret);
+		return ret;
+	}
+
+	kserdes_dfe_offset_calibration(sc, &sofs);
+
+	for (i = 0; i < sc->lanes; i++)
+		_kserdes_enable_xgmii_port(sc->peripheral_regmap, i);
+
+	_kserdes_wait_link_up(sc->dev, sc->regs, sc->pcsr_regmap,
+			      sc->lanes, lanes_enable);
+
+	return lanes_enable;
+}
+
+static inline void kserdes_xfw_get_lane_params(struct kserdes_config *sc,
+					       int lane)
+{
+	struct kserdes_fw_config *fw = &sc->fw;
+	u32 tx_ctrl, val_0, val_1;
+	u32 phy_a = PHY_A(sc->regs);
+
+	val_0 = kserdes_readl(sc->regs, LANEX_REG(lane, 0x04));
+	val_1 = kserdes_readl(sc->regs, LANEX_REG(lane, 0x08));
+
+	tx_ctrl = ((((val_0 >> 18) & 0x1)    << 24) |	/* TX_CTRL_O_24 */
+		   (((val_1 >> 0)  & 0xffff) <<  8) |	/* TX_CTRL_O_23_8 */
+		   (((val_0 >> 24) & 0xff)   <<  0));	/* TX_CTRL_O_7_0 */
+
+	if (phy_a) {
+		fw->cm = (val_1 >> 12) & 0xf;
+		fw->c1 = (val_1 >> 0) & 0x1f;
+		fw->c2 = (val_1 >> 8) & 0xf;
+	} else {
+		fw->cm = (tx_ctrl >> 16) & 0xf;
+		fw->c1 = (tx_ctrl >> 8) & 0x1f;
+		fw->c2 = (tx_ctrl >> 13) & 0x7;
+		fw->c2 = fw->c2 | (((tx_ctrl >> 24) & 0x1) << 3);
+	}
+
+	val_0 = _kserdes_read_select_tbus(sc->regs, lane + 1,
+					  (phy_a ? 0x11 : 0x10));
+	fw->attn = (val_0 >> 4) & 0xf;
+	fw->boost = (val_0 >> 8) & 0xf;
+
+	val_0 = _kserdes_read_select_tbus(sc->regs, lane + 1, 0x5);
+	fw->dlpf = (val_0 >> 2) & 0x3ff;
+
+	val_0 = _kserdes_read_select_tbus(sc->regs, lane + 1, 0x6);
+	fw->cdrcal = (val_0 >> 3) & 0xff;
+}
+
+static inline void kserdes_xfw_mem_init(struct kserdes_config *sc)
+{
+	struct kserdes_fw_config *fw = &sc->fw;
+	u32 i, lane_config = 0, lanes = sc->lanes;
+
+	for (i = 0; i < lanes; i++)
+		lane_config = (lane_config << 8) |
+			(fw->lane_config[i] & 0xff);
+
+	lane_config <<= 8;
+
+	/* initialize internal parameter area */
+	kserdes_writel(sc->regs, MEM_ADR_REG, KSERDES_XFW_CONFIG_START_ADDR);
+
+	/* clean out unused config area */
+	for (i = KSERDES_XFW_CONFIG_START_ADDR;
+	     i < KSERDES_XFW_PARAM_START_ADDR; i += 4)
+		kserdes_writel(sc->regs, MEM_DATINC_REG, 0x00000000);
+
+	/* Flush 64 bytes 10,11,12,13 */
+	kserdes_writel(sc->regs, MEM_DATINC_REG, 0x00009C9C);
+
+	/* fast train */
+	kserdes_writel(sc->regs, MEM_DATINC_REG, fw->fast_train);
+
+	kserdes_writel(sc->regs, MEM_DATINC_REG, 0x00000000);
+	/* lane seeds */
+	kserdes_writel(sc->regs, MEM_DATINC_REG, fw->lane_seeds);
+	/* lane config */
+	kserdes_writel(sc->regs, MEM_DATINC_REG, lane_config);
+}
+
+static int kserdes_xge_init(struct kserdes_config *sc)
+{
+	return kserdes_load_init_fw(sc, ks2_xgbe_serdes_firmwares,
+				    ARRAY_SIZE(ks2_xgbe_serdes_firmwares));
+}
+
+static int kserdes_pcie_lanes_enable(struct kserdes_config *sc)
+{
+	int ret, i;
+	u32 lanes_enable = 0;
+
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		lanes_enable |= (1 << i);
+	}
+
+	for (i = 0; i < sc->lanes; i++) {
+		kserdes_release_reset(sc, i);
+
+		if (sc->lane[i].loopback)
+			_kserdes_set_lane_loopback(sc->regs, i, sc->link_rate);
+	}
+
+	ret = kserdes_get_status(sc);
+	if (ret)
+		return ret;
+	else
+		return lanes_enable;
+}
+
+static int kserdes_pcie_init(struct kserdes_config *sc)
+{
+	return kserdes_load_init_fw(sc, ks2_pcie_serdes_firmwares,
+				    ARRAY_SIZE(ks2_pcie_serdes_firmwares));
+}
+
+static int kserdes_lanes_enable(struct kserdes_config *sc)
+{
+	switch (sc->phy_type) {
+	case KSERDES_PHY_SGMII:
+		return kserdes_sgmii_lanes_enable(sc);
+	case KSERDES_PHY_XGE:
+		return kserdes_xge_lanes_enable(sc);
+	case KSERDES_PHY_PCIE:
+		return kserdes_pcie_lanes_enable(sc);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int kserdes_init(struct phy *phy)
+{
+	struct kserdes_dev *sd = phy_get_drvdata(phy);
+	struct kserdes_config *sc = &sd->sc;
+	int ret;
+
+	switch (sc->phy_type) {
+	case KSERDES_PHY_SGMII:
+		ret = kserdes_sgmii_init(sc);
+		break;
+	case KSERDES_PHY_XGE:
+		ret = kserdes_xge_init(sc);
+		break;
+	case KSERDES_PHY_PCIE:
+		ret = kserdes_pcie_init(sc);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret < 0) {
+		dev_err(sd->dev, "serdes initialization failed %d\n", ret);
+		goto done;
+	}
+
+	ret = kserdes_lanes_enable(sc);
+	if (ret < 0) {
+		dev_err(sd->dev, "serdes lanes enable failed: %d\n", ret);
+		goto done;
+	}
+
+	dev_dbg(sd->dev, "serdes config done lanes(mask) 0x%x\n", ret);
+
+done:
+	return ret;
+}
+
+static int kserdes_of_parse_lane(struct device *dev,
+				 struct device_node *np,
+				 struct kserdes_config *sc)
+{
+	struct kserdes_lane_config *lc;
+	struct kserdes_equalizer *eq;
+	struct kserdes_tx_coeff *tc;
+	int lane_num, ret;
+
+	ret = of_property_read_u32(np, "reg", &lane_num);
+	if (ret) {
+		dev_err(dev, "Failed to parse reg\n");
+		return -EINVAL;
+	}
+
+	if (lane_num >= sc->lanes) {
+		dev_err(dev, "Invalid lane number %u\n", lane_num);
+		return -EINVAL;
+	}
+
+	lc = &sc->lane[lane_num];
+	lc->enable = true;
+	dev_dbg(dev, "lane %d enabled\n", lane_num);
+
+	if (of_property_read_u32(np, "control-rate", &lc->ctrl_rate)) {
+		dev_info(dev, "use default lane control-rate: %u\n",
+			 lc->ctrl_rate);
+	}
+	dev_dbg(dev, "lane control-rate: %d\n", lc->ctrl_rate);
+
+	if (of_find_property(np, "loopback", NULL))
+		lc->loopback = true;
+	else
+		lc->loopback = false;
+
+	dev_dbg(dev, "lane loopback: %d\n", lc->loopback);
+
+	eq = &lc->rx_start;
+	if (of_property_read_u32_array(np, "rx-start", &eq->att, 2)) {
+		dev_info(dev, "use default lane rx-start 0 0\n");
+		eq->att = 0;
+		eq->boost = 0;
+	}
+	dev_dbg(dev, "lane rx-start: %d %d\n", eq->att, eq->boost);
+
+	eq = &lc->rx_force;
+	if (of_property_read_u32_array(np, "rx-force", &eq->att, 2)) {
+		dev_info(dev, "use default lane rx-force 0 0\n");
+		eq->att = 0;
+		eq->boost = 0;
+	}
+	dev_dbg(dev, "lane rx-force: %d %d\n", eq->att, eq->boost);
+
+	tc = &lc->tx_coeff;
+	if (of_property_read_u32_array(np, "tx-coeff", &tc->c1, 5)) {
+		dev_info(dev, "use default tx-coeff 0\n");
+		tc->c1 = 0;
+	}
+	dev_dbg(dev, "tx-coeff: %d %d %d %d %d\n",
+		tc->c1, tc->c2, tc->cm, tc->att, tc->vreg);
+
+	return 0;
+}
+
+static void kserdes_set_sgmii_defaults(struct kserdes_config *sc)
+{
+	int i;
+
+	sc->link_rate		= KSERDES_LINK_RATE_1P25G;
+	sc->lanes		= 4;
+	sc->rx_force_enable	= false;
+
+	for (i = 0; i < sc->lanes; i++) {
+		memset(&sc->lane[i], 0, sizeof(sc->lane[i]));
+		sc->lane[i].ctrl_rate = KSERDES_QUARTER_RATE;
+	}
+}
+
+static void kserdes_set_xge_defaults(struct kserdes_config *sc)
+{
+	int i;
+
+	sc->link_rate		= KSERDES_LINK_RATE_10P3125G;
+	sc->lanes		= 2;
+	sc->rx_force_enable	= false;
+
+	for (i = 0; i < sc->lanes; i++) {
+		memset(&sc->lane[i], 0, sizeof(sc->lane[i]));
+		sc->lane[i].ctrl_rate = KSERDES_FULL_RATE;
+	}
+}
+
+static void kserdes_set_pcie_defaults(struct kserdes_config *sc)
+{
+	int i;
+
+	sc->link_rate		= KSERDES_LINK_RATE_5G;
+	sc->lanes		= 2;
+	sc->rx_force_enable	= false;
+
+	for (i = 0; i < sc->lanes; i++)
+		memset(&sc->lane[i], 0, sizeof(sc->lane[i]));
+}
+
+static void kserdes_set_defaults(struct kserdes_config *sc,
+				 enum KSERDES_PHY_TYPE phy_type)
+{
+	switch (phy_type) {
+	case KSERDES_PHY_SGMII:
+		kserdes_set_sgmii_defaults(sc);
+		break;
+	case KSERDES_PHY_XGE:
+		kserdes_set_xge_defaults(sc);
+		break;
+	case KSERDES_PHY_PCIE:
+		kserdes_set_pcie_defaults(sc);
+		break;
+	default:
+		break;
+	}
+}
+
+static int kserdes_of_parse(struct kserdes_dev *sd,
+			    struct device_node *np)
+{
+	struct kserdes_config *sc = &sd->sc;
+	struct device_node *lanes_np, *child;
+	struct device *dev = sd->dev;
+	struct resource res;
+	void __iomem *regs;
+	int ret;
+
+	ret = of_address_to_resource(np, SERDES_REG_INDEX, &res);
+	if (ret) {
+		dev_err(dev, "Can't xlate serdes reg addr of node(%s)\n",
+			np->name);
+		return ret;
+	}
+
+	regs = devm_ioremap_resource(dev, &res);
+	if (IS_ERR(regs)) {
+		dev_err(dev, "Failed to map serdes register base\n");
+		return PTR_ERR(regs);
+	}
+	sc->regs = regs;
+
+	if (of_device_is_compatible(np, "ti,keystone-serdes-gbe")) {
+		sc->phy_type = KSERDES_PHY_SGMII;
+	} else if (of_device_is_compatible(np, "ti,keystone-serdes-xgbe")) {
+		sc->phy_type = KSERDES_PHY_XGE;
+	} else if (of_device_is_compatible(np, "ti,keystone-serdes-pcie")) {
+		sc->phy_type = KSERDES_PHY_PCIE;
+	} else {
+		dev_err(dev, "unknown phy type\n");
+		return -EINVAL;
+	}
+
+	sc->dev = dev;
+
+	/* Set the defaults base on phy type */
+	kserdes_set_defaults(sc, sc->phy_type);
+
+	sc->peripheral_regmap =
+		syscon_regmap_lookup_by_phandle(np, "syscon-peripheral");
+	if (!sc->peripheral_regmap && IS_ERR(sc->peripheral_regmap)) {
+		dev_err(sc->dev,
+			"failed to get syscon-peripheral regmap\n");
+		return PTR_ERR(sc->peripheral_regmap);
+	}
+
+	sc->pcsr_regmap = syscon_regmap_lookup_by_phandle(np, "syscon-link");
+	if (!sc->pcsr_regmap && IS_ERR(sc->pcsr_regmap)) {
+		dev_err(sc->dev,
+			"failed to get syscon-link regmap\n");
+		return PTR_ERR(sc->pcsr_regmap);
+	}
+
+	if (of_property_read_u32(np, "link-rate-kbps", &sc->link_rate)) {
+		dev_info(dev, "use default link-rate-kbps: %u\n",
+			 sc->link_rate);
+	}
+
+	if (of_property_read_u32(np, "num-lanes", &sc->lanes))
+		dev_info(dev, "use default num-lanes %d\n", sc->lanes);
+
+	if (sc->lanes > KSERDES_MAX_LANES) {
+		sc->lanes = KSERDES_MAX_LANES;
+		dev_info(dev, "use max allowed lanes %d\n", sc->lanes);
+	}
+
+	if (of_property_read_bool(np, "rx-force-enable"))
+		sc->rx_force_enable = true;
+	else
+		sc->rx_force_enable = false;
+
+	lanes_np = of_get_child_by_name(np, "lanes");
+	if (lanes_np) {
+		for_each_available_child_of_node(lanes_np, child) {
+			ret = kserdes_of_parse_lane(dev, child, sc);
+			if (ret) {
+				of_node_put(child);
+				of_node_put(lanes_np);
+				return ret;
+			}
+			of_node_put(child);
+		}
+		of_node_put(lanes_np);
+	}
+
+	return 0;
+}
+
+static struct phy_ops kserdes_ops = {
+	.init		= kserdes_init,
+	.owner		= THIS_MODULE,
+};
+
+static int kserdes_probe(struct platform_device *pdev)
+{
+	struct phy_provider *phy_provider;
+	struct kserdes_dev *sd;
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	sd = devm_kzalloc(dev, sizeof(*sd), GFP_KERNEL);
+	if (!sd)
+		return -ENOMEM;
+
+	sd->dev = dev;
+
+	ret = kserdes_of_parse(sd, np);
+	if (ret)
+		return ret;
+
+	dev_set_drvdata(dev, sd);
+	sd->phy = devm_phy_create(dev, NULL, &kserdes_ops);
+	if (IS_ERR(sd->phy))
+		return PTR_ERR(sd->phy);
+
+	phy_set_drvdata(sd->phy, sd);
+	phy_provider = devm_of_phy_provider_register(sd->dev,
+						     of_phy_simple_xlate);
+
+	if (IS_ERR(phy_provider))
+		return PTR_ERR_OR_ZERO(phy_provider);
+
+	dev_vdbg(&pdev->dev, "probed");
+	return 0;
+}
+
+static const struct of_device_id kserdes_of_match[] = {
+	{ .compatible = "ti,keystone-serdes-gbe" },
+	{ .compatible = "ti,keystone-serdes-pcie" },
+	{ .compatible = "ti,keystone-serdes-xgbe" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, kserdes_of_match);
+
+static struct platform_driver kserdes_driver = {
+	.probe	= kserdes_probe,
+	.driver = {
+		.of_match_table	= kserdes_of_match,
+		.name  = "ti,keystone-serdes",
+	}
+};
+
+static int __init keystone_serdes_phy_init(void)
+{
+	return platform_driver_register(&kserdes_driver);
+}
+module_init(keystone_serdes_phy_init);
+
+static void __exit keystone_serdes_phy_exit(void)
+{
+	platform_driver_unregister(&kserdes_driver);
+}
+module_exit(keystone_serdes_phy_exit);
+
+MODULE_AUTHOR("WingMan Kwok <w-kwok2@ti.com>");
+MODULE_DESCRIPTION("TI Keystone SerDes driver");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 14:25   ` WingMan Kwok
  0 siblings, 0 replies; 63+ messages in thread
From: WingMan Kwok @ 2015-10-15 14:25 UTC (permalink / raw
  To: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, kishon,
	rogerq, m-karicheri2, bhelgaas, ssantosh, linux, devicetree,
	linux-kernel, linux-pci, linux-arm-kernel
  Cc: WingMan Kwok

On TI's Keystone platforms, several peripherals such as the
gbe ethernet switch, 10gbe ethernet switch and PCIe controller
require the use of a SerDes for converting SoC parallel data into
serialized data that can be output over a high-speed electrical
interface, and also converting high-speed serial input data
into parallel data that can be processed by the SoC.  The
SerDeses used by those peripherals, though they may be different,
are largely similar in functionality and setup.

This patch provides a SerDes phy driver implementation that can be
used by the above mentioned peripheral drivers to configure their
respective SerDeses.

v1:
	- see cover letter for review comments addressed.

Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
---
 Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
 drivers/phy/Kconfig                              |    8 +
 drivers/phy/Makefile                             |    1 +
 drivers/phy/phy-keystone-serdes.c                | 2373 ++++++++++++++++++++++
 4 files changed, 2660 insertions(+)
 create mode 100644 drivers/phy/phy-keystone-serdes.c

diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt
index 9cf9446..4dca271 100644
--- a/Documentation/devicetree/bindings/phy/ti-phy.txt
+++ b/Documentation/devicetree/bindings/phy/ti-phy.txt
@@ -115,4 +115,282 @@ sata_phy: phy@4A096000 {
 	clock-names = "sysclk", "refclk";
 	syscon-pllreset = <&scm_conf 0x3fc>;
 	#phy-cells = <0>;
+
+TI Keystone SerDes PHY
+======================
+
+Required properties:
+ - compatible: should be one of
+	* "ti,keystone-serdes-gbe"
+	* "ti,keystone-serdes-xgbe"
+	* "ti,keystone-serdes-pcie"
+ - reg:
+	* base address and length of the SerDes register set
+ - reg-names:
+	* "serdes"
+		- name of the reg SerDes register set
+ - #phy-cells:
+	* From the generic phy bindings, must be 0;
+ - num-lanes:
+	* Number of lanes in SerDes.
+
+Optional properties:
+ - syscon-peripheral:
+	* Handle to the subsystem register region of the peripheral
+	  inside which the SerDes exists.
+ - syscon-link:
+	* Handle to the Link register region of the peripheral inside
+	  which the SerDes exists.  Example: it is the PCSR register
+	  region in the case of 10gbe.
+ - rx-force-enable:
+	* Include this property if receiver attenuation and boost are
+	  to be configured with specific values defined in rx-force.
+ - link-rate-kbps:
+	* SerDes link rate to be configured, in kbps.
+
+
+For gbe and 10gbe SerDes, it is optional to represent each lane as
+a sub-node, which can be enabled or disabled individually using
+the "status" property.
+
+Required properties (lane sub-node):
+ - reg:
+	* lane number
+
+Optional properties (lane sub-node):
+ - control-rate:
+	* Lane control rate
+		0: full rate
+		1: half rate
+		2: quarter rate
+ - rx-start:
+	* Initial lane rx equalizer attenuation and boost configurations.
+	* Must be array of 2 integers.
+ - rx-force:
+	* Forced lane rx equalizer attenuation and boost configurations.
+	* Must be array of 2 integers.
+ - tx-coeff:
+	* Lane c1, c2, cm, attenuation and regulator output voltage
+	  configurations.
+	* Must be array of 5 integers.
+ - loopback:
+	* Include this property to enable loopback at the SerDes
+	  lane level.
+
+Example for Keystone K2E GBE:
+-----------------------------
+
+gbe_serdes0: gbe_serdes@232a000 {
+	#phy-cells		= <0>;
+	compatible		= "ti,keystone-serdes-gbe";
+	reg			= <0x0232a000 0x2000>;
+	reg-names		= "serdes";
+	link-rate-kbps		= <1250000>;
+	num-lanes		= <4>;
+	lanes {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		lane@0 {
+			/*loopback;*/
+			reg		= <0>;
+			control-rate	= <2>; /* quart */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <0 0 0 12 4>;
+			       /* c1 c2 cm att vreg */
+		};
+		lane@1 {
+			/*loopback;*/
+			reg		= <1>;
+			control-rate	= <2>; /* quart */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <0 0 0 12 4>;
+			       /* c1 c2 cm att vreg */
+		};
+	};
+};
+
+gbe_serdes1: gbe_serdes@2324000 {
+	#phy-cells		= <0>;
+	compatible		= "ti,keystone-serdes-gbe";
+	reg			= <0x02324000 0x2000>;
+	reg-names		= "serdes";
+	link-rate-kbps		= <1250000>;
+	num-lanes		= <4>;
+	lanes {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		lane@0 {
+			/*loopback;*/
+			reg		= <0>;
+			control-rate	= <2>; /* quart */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <0 0 0 12 4>;
+			       /* c1 c2 cm att vreg */
+		};
+		lane@1 {
+			/*loopback;*/
+			reg		= <1>;
+			control-rate	= <2>; /* quart */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <0 0 0 12 4>;
+			       /* c1 c2 cm att vreg */
+		};
+	};
+};
+
+netcp: netcp@24000000 {
+	...
+
+	netcp-devices {
+		...
+
+		gbe@200000 { /* ETHSS */
+			...
+			serdeses {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				serdes@0 {
+					reg = <0>;
+					phys = <&gbe_serdes0>;
+					status = "ok";
+				};
+				serdes@1 {
+					reg = <1>;
+					phys = <&gbe_serdes1>;
+					status = "ok";
+				};
+
+			...
+			};
+
+		...
+		};
+
+	...
+	};
+};
+
+Example for Keystone PCIE:
+--------------------------
+
+	pcie0_phy: serdes_phy@2320000 {
+		#phy-cells = <0>;
+		compatible = "ti,keystone-serdes-pcie";
+		reg = <0x02320000 0x4000>;
+		reg-names = "serdes";
+		num-lanes = <2>;
+	};
+
+
+Then the PHY can be used in PCIe controller node as
+
+	pcie0: pcie@21800000 {
+		...
+
+		serdeses {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			serdes@0 {
+				reg = <0>;
+				phys = <&pcie0_phy>;
+				status = "disabled";
+			};
+		};
+	}
+
+Example for K2E 10GBE:
+----------------------
+
+Define the syscon regmaps for 10gbe subsystem:
+
+xgbe_subsys: xgbe_subsys@2f00000 {
+	status		= "ok";
+	compatible	= "syscon";
+	reg		= <0x02f00000 0x100>;
+};
+
+Define the syscon regmaps for 10gbe pcsr:
+
+xgbe_pcsr: xgbe_pcsr@2f00000 {
+	status		= "ok";
+	compatible	= "syscon";
+	reg		= <0x02f00600 0x100>;
+};
+
+Define the 10gbe SerDes node:
+
+xgbe_serdes: xgbe_serdes@231e000 {
+	status			= "ok";
+	#phy-cells		= <0>;
+	compatible		= "ti,keystone-serdes-xgbe";
+	reg			= <0x0231e000 0x2000>;
+	reg-names		= "serdes";
+	link-rate-kbps		= <10312500>;
+	num-lanes		= <2>;
+	syscon-peripheral	= <&xgbe_subsys>;
+	syscon-link		= <&xgbe_pcsr>;
+	lanes {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		lane@0 {
+			/*loopback;*/
+			reg		= <0>;
+			control-rate	= <0>; /* full */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <2 0 0 12 4>;
+				/* c1 c2 cm att vreg */
+		};
+		lane@1 {
+			/*loopback;*/
+			reg		= <1>;
+			control-rate	= <0>; /* full */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <2 0 0 12 4>;
+				/* c1 c2 cm att vreg */
+		};
+	};
+};
+
+Then the 10gbe SerDes PHY can be used in the 10gbe switch node:
+
+netcpx: netcpx@2f00000 {
+
+	...
+
+	netcp-devices {
+
+		...
+
+		xgbe@2f00000 {
+
+			...
+
+			syscon-subsys = <&xgbe_subsys>;
+			syscon-link = <&xgbe_pcsr>;
+
+			...
+
+			serdeses {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				serdes@0 {
+					reg = <0>;
+					phys = <&xgbe_serdes>;
+				};
+			};
+
+
+			...
+
+		};
+	};
+
+	...
+
 };
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 47da573..8fc21a4 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -118,6 +118,14 @@ config PHY_RCAR_GEN2
 	help
 	  Support for USB PHY found on Renesas R-Car generation 2 SoCs.
 
+config PHY_TI_KEYSTONE_SERDES
+	tristate "TI Keystone SerDes PHY support"
+	depends on OF && ARCH_KEYSTONE
+	select GENERIC_PHY
+	help
+	  This option enables support for TI Keystone SerDes PHY found
+	  in peripherals GBE, 10GBE and PCIe.
+
 config OMAP_CONTROL_PHY
 	tristate "OMAP CONTROL PHY Driver"
 	depends on ARCH_OMAP2PLUS || COMPILE_TEST
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index a5b18c1..8cb365b 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -46,3 +46,4 @@ obj-$(CONFIG_PHY_QCOM_UFS) 	+= phy-qcom-ufs-qmp-14nm.o
 obj-$(CONFIG_PHY_TUSB1210)		+= phy-tusb1210.o
 obj-$(CONFIG_PHY_BRCMSTB_SATA)		+= phy-brcmstb-sata.o
 obj-$(CONFIG_PHY_PISTACHIO_USB)		+= phy-pistachio-usb.o
+obj-$(CONFIG_PHY_TI_KEYSTONE_SERDES)	+= phy-keystone-serdes.o
diff --git a/drivers/phy/phy-keystone-serdes.c b/drivers/phy/phy-keystone-serdes.c
new file mode 100644
index 0000000..f213006
--- /dev/null
+++ b/drivers/phy/phy-keystone-serdes.c
@@ -0,0 +1,2373 @@
+/*
+ * Texas Instruments Keystone SerDes driver
+ * Authors: WingMan Kwok <w-kwok2@ti.com>
+ *
+ * This is the SerDes Phy driver for Keystone devices. This is
+ * required to support PCIe RC functionality based on designware
+ * PCIe hardware, gbe and 10gbe found on these devices.
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The contents of the array k2_100mhz_pcie_5gbps_serdes is covered by BSD
+ * license.
+ */
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/firmware.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+/*
+ * Keystone2 SERDES registers
+ */
+/* 0x1fc0 - 0x1fff */
+#define KSERDES_SS_OFFSET	0x1fc0
+/* 0x1fc0 */
+#define MOD_VER_REG		(KSERDES_SS_OFFSET + 0x00)
+/* 0x1fc4 */
+#define MEM_ADR_REG		(KSERDES_SS_OFFSET + 0x04)
+/* 0x1fc8 */
+#define MEM_DAT_REG		(KSERDES_SS_OFFSET + 0x08)
+/* 0x1fcc */
+#define MEM_DATINC_REG		(KSERDES_SS_OFFSET + 0x0c)
+/* 0x1fd0 */
+#define CPU_CTRL_REG		(KSERDES_SS_OFFSET + 0x10)
+/* 0x1fe0, 0x1fe4 */
+#define LANE_CTRL_STS_REG(x)	(KSERDES_SS_OFFSET + 0x20 + (x * 0x04))
+/* 0x1ff0 */
+#define LINK_LOSS_WAIT_REG	(KSERDES_SS_OFFSET + 0x30)
+/* 0x1ff4 */
+#define PLL_CTRL_REG		(KSERDES_SS_OFFSET + 0x34)
+
+/* CMU0 SS 0x0000 - 0x01ff */
+#define CMU0_SS_OFFSET		0x0000
+#define CMU0_REG(x)		(CMU0_SS_OFFSET + x)
+
+/* LANE SS 0x0200 - 0x03ff, 0x0400 - 0x05ff, ... */
+#define LANE0_SS_OFFSET		0x0200
+#define LANEX_SS_OFFSET(x)	(LANE0_SS_OFFSET * (x + 1))
+#define LANEX_REG(x, y)		(LANEX_SS_OFFSET(x) + y)
+
+/* CML SS 0x0a00 - 0x0bff */
+#define CML_SS_OFFSET		0x0a00
+#define CML_REG(x)		(CML_SS_OFFSET + x)
+
+/* CMU1 SS 0x0c00 - 0x0dff */
+#define CMU1_SS_OFFSET		0x0c00
+#define CMU1_REG(x)		(CMU1_SS_OFFSET + x)
+
+/*
+ * XGE PCS-R registers
+ */
+#define PCSR_OFFSET(x)		(x * 0x80)
+
+#define PCSR_TX_CTL(x)		(PCSR_OFFSET(x) + 0x00)
+#define PCSR_TX_STATUS(x)	(PCSR_OFFSET(x) + 0x04)
+#define PCSR_RX_CTL(x)		(PCSR_OFFSET(x) + 0x08)
+#define PCSR_RX_STATUS(x)	(PCSR_OFFSET(x) + 0x0C)
+
+#define XGE_CTRL_OFFSET		0x0c
+#define PCIE_PL_GEN2_OFFSET	0x180c
+
+#define reg_rmw(addr, value, mask) \
+	__raw_writel(((__raw_readl(addr) & (~(mask))) | \
+			(value & (mask))), (addr))
+
+/* Replaces bit field [msb:lsb] in register located
+ * at (base + offset) by val
+ */
+#define FINSR(base, offset, msb, lsb, val) \
+	reg_rmw((base) + (offset), ((val) << (lsb)), GENMASK((msb), (lsb)))
+
+/* This version of FEXTR is NOT safe for msb = 31, lsb = 0
+ * but then why would we need FEXTR for that case.
+ */
+#define FEXTR(val, msb, lsb) \
+	(((val) >> (lsb)) & ((1 << ((msb) - (lsb) + 1)) - 1))
+
+#define MOD_VER(serdes) \
+	((kserdes_readl(serdes, MOD_VER_REG) >> 16) & 0xffff)
+
+#define PHY_A(serdes) (MOD_VER(serdes) != 0x4eba)
+
+#define FOUR_LANE(serdes) \
+	((MOD_VER(serdes) == 0x4eb9) || (MOD_VER(serdes) == 0x4ebd))
+
+#define LANE_ENABLE(sc, n) ((sc)->lane[n].enable)
+
+#define for_each_enable_lane(func, sc)			\
+	do {						\
+		int i;					\
+		for (i = 0; i < (sc)->lanes; i++) {	\
+			if (!LANE_ENABLE((sc), i))	\
+				continue;		\
+							\
+			(func)((sc), i);		\
+		}					\
+	} while (0)
+
+#define for_each_lane(func, sc)				\
+	do {						\
+		int i;					\
+		for (i = 0; i < (sc)->lanes; i++) {	\
+			(func)((sc), i);		\
+		}					\
+	} while (0)
+
+#define for_each_enable_lane_return(func, sc, r)	\
+	do {						\
+		int i;					\
+		(r) = 0;				\
+		for (i = 0; i < (sc)->lanes; i++) {	\
+			if (!LANE_ENABLE((sc), i))	\
+				continue;		\
+							\
+			(r) = (func)((sc), i);		\
+			if ((r))			\
+				break;			\
+		}					\
+	} while (0)
+
+#define MAX_COMPARATORS			5
+#define DFE_OFFSET_SAMPLES		100
+
+/* CPU CTRL bits */
+#define CPU_EN			BIT(31)
+#define CPU_GO			BIT(30)
+#define POR_EN			BIT(29)
+#define CPUREG_EN		BIT(28)
+#define AUTONEG_CTL		BIT(27)
+#define DATASPLIT		BIT(26)
+#define LNKTRN_SIG_DET		BIT(8)
+
+#define ANEG_LINK_CTL_10GKR_MASK	GENMASK(21, 20)
+#define ANEG_LINK_CTL_1GKX_MASK		GENMASK(17, 16)
+#define ANEG_LINK_CTL_1G10G_MASK \
+	(ANEG_LINK_CTL_10GKR_MASK | ANEG_LINK_CTL_1GKX_MASK)
+
+#define ANEG_1G_10G_OPT_MASK		GENMASK(7, 5)
+
+#define SERDES_REG_INDEX		0
+
+/* SERDES internal memory */
+#define KSERDES_XFW_MEM_SIZE		SZ_64K
+#define KSERDES_XFW_CONFIG_MEM_SIZE	SZ_64
+#define KSERDES_XFW_NUM_PARAMS		5
+
+/* Last 64B of the 64KB internal mem is for parameters */
+#define KSERDES_XFW_CONFIG_START_ADDR \
+	(KSERDES_XFW_MEM_SIZE - KSERDES_XFW_CONFIG_MEM_SIZE)
+
+#define KSERDES_XFW_PARAM_START_ADDR \
+	(KSERDES_XFW_MEM_SIZE - (KSERDES_XFW_NUM_PARAMS * 4))
+
+/* All firmware file names end up here. List the firmware file names below.
+ * Newest first. Search starts from the 0-th array entry until a firmware
+ * file is found.
+ */
+const char *ks2_gbe_serdes_firmwares[] = {"ks2_gbe_serdes.bin"};
+const char *ks2_xgbe_serdes_firmwares[] = {"ks2_xgbe_serdes.bin"};
+const char *ks2_pcie_serdes_firmwares[] = {"ks2_pcie_serdes.bin"};
+
+/* SERDES Link Rate Kbps */
+enum KSERDES_LINK_RATE {
+	KSERDES_LINK_RATE_1P25G		=  1250000,
+	KSERDES_LINK_RATE_3P125G	=  3125000,
+	KSERDES_LINK_RATE_4P9152G	=  4915200,
+	KSERDES_LINK_RATE_5G		=  5000000,
+	KSERDES_LINK_RATE_6P144G	=  6144000,
+	KSERDES_LINK_RATE_6P25G		=  6250000,
+	KSERDES_LINK_RATE_7P3728G	=  7372800,
+	KSERDES_LINK_RATE_9P8304G	=  9830400,
+	KSERDES_LINK_RATE_10G		= 10000000,
+	KSERDES_LINK_RATE_10P3125G	= 10312500,
+	KSERDES_LINK_RATE_12P5G		= 12500000,
+};
+
+/* SERDES Lane Control Rate */
+enum KSERDES_LANE_CTRL_RATE {
+	KSERDES_FULL_RATE,
+	KSERDES_HALF_RATE,
+	KSERDES_QUARTER_RATE,
+};
+
+enum KSERDES_PHY_TYPE {
+	KSERDES_PHY_SGMII,
+	KSERDES_PHY_XGE,
+	KSERDES_PHY_PCIE,
+	KSERDES_PHY_HYPERLINK,
+};
+
+struct kserdes_tx_coeff {
+	u32	c1;
+	u32	c2;
+	u32	cm;
+	u32	att;
+	u32	vreg;
+};
+
+struct kserdes_equalizer {
+	u32	att;
+	u32	boost;
+};
+
+struct kserdes_lane_config {
+	bool				enable;
+	u32				ctrl_rate;
+	struct kserdes_tx_coeff		tx_coeff;
+	struct kserdes_equalizer	rx_start;
+	struct kserdes_equalizer	rx_force;
+	bool				loopback;
+};
+
+#define KSERDES_MAX_LANES		4
+
+struct kserdes_fw_config {
+	bool				on;
+	u32				rate;
+	u32				link_loss_wait;
+	u32				lane_seeds;
+	u32				fast_train;
+	u32				active_lane;
+	u32				c1, c2, cm, attn, boost, dlpf, cdrcal;
+	u32				lane_config[KSERDES_MAX_LANES];
+};
+
+struct kserdes_config {
+	struct device			*dev;
+	enum KSERDES_PHY_TYPE		phy_type;
+	u32				lanes;
+	void __iomem			*regs;
+	struct regmap			*peripheral_regmap;
+	struct regmap			*pcsr_regmap;
+	/* non-fw specific */
+	const char			*init_fw;
+	struct serdes_cfg		*init_cfg;
+	int				init_cfg_len;
+	enum KSERDES_LINK_RATE		link_rate;
+	bool				rx_force_enable;
+	struct kserdes_lane_config	lane[KSERDES_MAX_LANES];
+	/* fw specific */
+	bool				firmware;
+	struct kserdes_fw_config	fw;
+};
+
+struct kserdes_dev {
+	struct device *dev;
+	struct phy *phy;
+	struct kserdes_config sc;
+};
+
+struct kserdes_comparator_tap_offsets {
+	u32 cmp;
+	u32 tap1;
+	u32 tap2;
+	u32 tap3;
+	u32 tap4;
+	u32 tap5;
+};
+
+struct kserdes_lane_offsets {
+	struct kserdes_comparator_tap_offsets ct_ofs[MAX_COMPARATORS];
+};
+
+struct kserdes_offsets {
+	struct kserdes_lane_offsets lane_ofs[KSERDES_MAX_LANES];
+};
+
+struct serdes_cfg {
+	u32 ofs;
+	u32 msb;
+	u32 lsb;
+	u32 val;
+};
+
+static inline u32 kserdes_readl(void __iomem *base, u32 offset)
+{
+	return readl(base + offset);
+}
+
+static inline void kserdes_writel(void __iomem *base, u32 offset, u32 value)
+{
+	writel(value, base + offset);
+}
+
+static void kserdes_do_config(void __iomem *base,
+			      struct serdes_cfg *cfg, u32 size)
+{
+	u32 i;
+
+	for (i = 0; i < size; i++)
+		FINSR(base, cfg[i].ofs, cfg[i].msb, cfg[i].lsb, cfg[i].val);
+}
+
+static int kserdes_load_init_fw(struct kserdes_config *sc,
+				const char **a_firmwares,
+				int n_firmwares)
+{
+	const struct firmware *fw;
+	bool found = false;
+	int ret, i;
+
+	for (i = 0; i < n_firmwares; i++) {
+		if (a_firmwares[i]) {
+			ret = request_firmware(&fw, a_firmwares[i], sc->dev);
+			if (!ret) {
+				found = true;
+				break;
+			}
+		}
+	}
+
+	if (!found) {
+		dev_err(sc->dev, "can't get any serdes init fw");
+		return -ENODEV;
+	}
+
+	sc->init_fw = a_firmwares[i];
+	sc->init_cfg = devm_kzalloc(sc->dev, fw->size, GFP_KERNEL);
+	memcpy((void *)sc->init_cfg, fw->data,  fw->size);
+	sc->init_cfg_len = fw->size;
+	release_firmware(fw);
+
+	kserdes_do_config(sc->regs, sc->init_cfg,
+			  sc->init_cfg_len / sizeof(struct serdes_cfg));
+
+	return 0;
+}
+
+static inline u32 _kserdes_read_tbus_val(void __iomem *sregs)
+{
+	u32 tmp;
+
+	if (PHY_A(sregs)) {
+		tmp  = ((kserdes_readl(sregs, CMU0_REG(0xec))) >> 24) & 0x0ff;
+		tmp |= ((kserdes_readl(sregs, CMU0_REG(0xfc))) >> 16) & 0xf00;
+	} else {
+		tmp  = ((kserdes_readl(sregs, CMU0_REG(0xf8))) >> 16) & 0xfff;
+	}
+
+	return tmp;
+}
+
+static void _kserdes_write_tbus_addr(void __iomem *sregs, int select, int ofs)
+{
+	if (select && !FOUR_LANE(sregs))
+		++select;
+
+	if (PHY_A(sregs))
+		FINSR(sregs, CMU0_REG(0x8), 31, 24, ((select << 5) + ofs));
+	else
+		FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((select << 8) + ofs));
+}
+
+static u32 _kserdes_read_select_tbus(void __iomem *sregs, int select, int ofs)
+{
+	/* set tbus address */
+	_kserdes_write_tbus_addr(sregs, select, ofs);
+	/* get tbus value */
+	return _kserdes_read_tbus_val(sregs);
+}
+
+static inline void kserdes_tap1_patch(struct kserdes_config *sc)
+{
+	FINSR(sc->regs, CML_REG(0xbc), 28, 24, 0x1e);
+}
+
+static inline void kserdes_set_tx_idle(struct kserdes_config *sc, u32 lane)
+{
+	if (sc->phy_type != KSERDES_PHY_XGE)
+		FINSR(sc->regs, LANEX_REG(lane, 0xb8), 17, 16, 3);
+
+	FINSR(sc->regs, LANE_CTRL_STS_REG(lane), 25, 24, 3);
+	FINSR(sc->regs, LANEX_REG(lane, 0x28), 21, 20, 0);
+}
+
+static inline void kserdes_clr_tx_idle(struct kserdes_config *sc, u32 lane)
+{
+	if (sc->phy_type != KSERDES_PHY_XGE)
+		FINSR(sc->regs, LANEX_REG(lane, 0xb8), 17, 16, 0);
+
+	FINSR(sc->regs, LANE_CTRL_STS_REG(lane), 25, 24, 0);
+	FINSR(sc->regs, LANEX_REG(lane, 0x28), 21, 20, 0);
+}
+
+static inline void kserdes_cdfe_enable(struct kserdes_config *sc, u32 lane)
+{
+	FINSR(sc->regs, LANEX_REG(lane, 0x94), 24, 24, 0x1);
+}
+
+static inline void kserdes_cdfe_force_calibration_enable(
+			struct kserdes_config *sc, u32 lane)
+{
+	FINSR(sc->regs, LANEX_REG(lane, 0x98), 0, 0, 0x1);
+}
+
+static void kserdes_phya_lane_patch(struct kserdes_config *sc, u32 lane)
+{
+	/* pma_ln_vreg */
+	FINSR(sc->regs, LANEX_REG(lane, 0x18), 25, 24, 0x2);
+	/* pma_ln_vregh */
+	FINSR(sc->regs, LANEX_REG(lane, 0x18), 27, 26, 0x2);
+	/* pma_int_step */
+	FINSR(sc->regs, LANEX_REG(lane, 0x14), 15, 13, 0x1);
+	/* turn off att_boost */
+	FINSR(sc->regs, LANEX_REG(lane, 0x4c), 19, 16, 0xf);
+	/* set dfe_bias to 10 */
+	FINSR(sc->regs, LANEX_REG(lane, 0x4c), 23, 20, 0xa);
+	/* Set offset average num of samples to max value */
+	FINSR(sc->regs, LANEX_REG(lane, 0x78), 30, 24, 0x7f);
+}
+
+static void kserdes_phyb_patch(struct kserdes_config *sc)
+{
+	/* Enables the Center DFE */
+	for_each_enable_lane(kserdes_cdfe_enable, sc);
+
+	/* setting initial cdfe */
+	FINSR(sc->regs, CML_REG(0x108), 23, 16, 0x04);
+
+	/* setting rx tap */
+	FINSR(sc->regs, CML_REG(0xbc), 28, 24, 0x0);
+
+	/* enable cdfe_ln_force_cal for cdfe */
+	for_each_lane(kserdes_cdfe_force_calibration_enable, sc);
+}
+
+static inline void kserdes_set_lane_starts(struct kserdes_config *sc, u32 lane)
+{
+	/* att start -1 for short channel */
+	FINSR(sc->regs, LANEX_REG(lane, 0x8c), 11, 8,
+	      sc->lane[lane].rx_start.att);
+	/* boost start -3 for short channel */
+	FINSR(sc->regs, LANEX_REG(lane, 0x8c), 15, 12,
+	      sc->lane[lane].rx_start.boost);
+}
+
+static void kserdes_phy_patch(struct kserdes_config *sc)
+{
+	if (sc->phy_type == KSERDES_PHY_XGE)
+		kserdes_phyb_patch(sc);
+	else if (sc->link_rate >= KSERDES_LINK_RATE_9P8304G)
+		for_each_enable_lane(kserdes_phya_lane_patch, sc);
+
+	/* Set ATT and BOOST start values for each lane */
+	for_each_enable_lane(kserdes_set_lane_starts, sc);
+}
+
+static inline void _kserdes_set_training_pattern(void __iomem *sregs)
+{
+	FINSR(sregs, CML_REG(0xc8), 5, 0, 0x0f);
+}
+
+static void kserdes_set_lane_overrides(struct kserdes_config *sc, u32 lane)
+{
+	u32 val_0, val_1, val;
+
+	/* read laneX_ctrl_i/laneX_pd_i */
+	val_0 = _kserdes_read_select_tbus(sc->regs, lane + 1, 0);
+
+	/* read laneX_rate_i */
+	val_1 = _kserdes_read_select_tbus(sc->regs, lane + 1, 1);
+
+	/* set RESET state */
+	val = 0;
+	/* user rate */
+	val |= ((val_1 >> 9) & 0x3) << 1;
+	/* user PD */
+	val |= (val_0 & 0x3) << 3;
+	/* user ctrl_i */
+	val |= ((val_0 >> 2) & 0x1ff) << 5;
+	/* set override */
+	val |= (1 << 14);
+	/* try claer TX Valid bits */
+	val &= ~0x60;
+
+	/* Only modify the reset bit and the overlay bit */
+	FINSR(sc->regs, LANEX_REG(lane, 0x028), 29, 15, val);
+}
+
+static inline void kserdes_assert_reset(struct kserdes_config *sc)
+{
+	for_each_enable_lane(kserdes_set_lane_overrides, sc);
+}
+
+static inline void kserdes_config_c1_c2_cm(struct kserdes_config *sc, u32 lane)
+{
+	u32 c1, c2, cm;
+
+	c1 = sc->lane[lane].tx_coeff.c1;
+	c2 = sc->lane[lane].tx_coeff.c2;
+	cm = sc->lane[lane].tx_coeff.cm;
+
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		/* TX Control override enable */
+		FINSR(sc->regs, LANEX_REG(lane, 0x8), 11,  8, (cm & 0xf));
+		FINSR(sc->regs, LANEX_REG(lane, 0x8),  4,  0, (c1 & 0x1f));
+		FINSR(sc->regs, LANEX_REG(lane, 0x8),  7,  5, (c2 & 0x7));
+		FINSR(sc->regs, LANEX_REG(lane, 0x4),
+		      18, 18, ((c2 >> 3) & 0x1));
+	} else {
+		FINSR(sc->regs, LANEX_REG(lane, 0x8), 15, 12, (cm & 0xf));
+		FINSR(sc->regs, LANEX_REG(lane, 0x8),  4,  0, (c1 & 0x1f));
+		FINSR(sc->regs, LANEX_REG(lane, 0x8), 11,  8, (c2 & 0xf));
+	}
+}
+
+static inline void kserdes_config_att_boost(struct kserdes_config *sc, u32 lane)
+{
+	u32 att, boost;
+
+	att = sc->lane[lane].rx_force.att;
+	boost = sc->lane[lane].rx_force.boost;
+
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		FINSR(sc->regs, LANEX_REG(lane, 0x98), 13, 13, 0);
+		FINSR(sc->regs, LANEX_REG(lane, 0x8c), 15, 12, boost);
+		FINSR(sc->regs, LANEX_REG(lane, 0x8c), 11, 8, att);
+	} else {
+		if (att != 1) {
+			FINSR(sc->regs, CML_REG(0x84), 0, 0, 0);
+			FINSR(sc->regs, CML_REG(0x8c), 24, 24, 0);
+			FINSR(sc->regs, LANEX_REG(lane, 0x8c), 11, 8, att);
+		}
+		if (boost != 1) {
+			FINSR(sc->regs, CML_REG(0x84), 1, 1, 0);
+			FINSR(sc->regs, CML_REG(0x8c), 25, 25, 0);
+			FINSR(sc->regs, LANEX_REG(lane, 0x8c), 15, 12, boost);
+		}
+	}
+}
+
+static void kserdes_set_tx_rx_fir_coeff(struct kserdes_config *sc, u32 lane)
+{
+	struct kserdes_tx_coeff *tc = &sc->lane[lane].tx_coeff;
+
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		/* Tx Swing */
+		FINSR(sc->regs, LANEX_REG(lane, 0x004), 29, 26, tc->att);
+		/* Regulator voltage */
+		FINSR(sc->regs, LANEX_REG(lane, 0x0a4), 2, 0, tc->vreg);
+	} else {
+		/* Tx Swing */
+		FINSR(sc->regs, LANEX_REG(lane, 0x004), 28, 25, tc->att);
+		/* Regulator voltage */
+		FINSR(sc->regs, LANEX_REG(lane, 0x084), 7, 5, tc->vreg);
+	}
+
+	kserdes_config_c1_c2_cm(sc, lane);
+
+	if (sc->rx_force_enable)
+		kserdes_config_att_boost(sc, lane);
+}
+
+static inline void _kserdes_force_signal_detect_low(
+				void __iomem *sregs, u32 lane)
+{
+	FINSR(sregs, LANEX_REG(lane, 0x004), 2, 1, 0x2);
+}
+
+static inline void kserdes_force_signal_detect_low(
+			struct kserdes_config *sc, u32 lane)
+{
+	_kserdes_force_signal_detect_low(sc->regs, lane);
+}
+
+static inline void _kserdes_force_signal_detect_high(
+				void __iomem *sregs, u32 lane)
+{
+	FINSR(sregs, LANEX_REG(lane, 0x004), 2, 1, 0x0);
+}
+
+static inline void kserdes_force_signal_detect_high(
+			struct kserdes_config *sc, u32 lane)
+{
+	_kserdes_force_signal_detect_high(sc->regs, lane);
+}
+
+static int kserdes_deassert_reset_poll_others(struct kserdes_config *sc)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(500);
+	u32 lanes_not_ok = 0;
+	u32 ofs = 28;
+	u32 ret, i;
+
+	/* assume all enable lanes not-ok (1) and all others
+	 * ok (0) to start
+	 */
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		lanes_not_ok |= (1 << i);
+	}
+
+	/* This is not a mistake.  For 2-laner, we
+	 * check bit 29 and 30,  NOT 28 and 29.
+	 */
+	if (!FOUR_LANE(sc->regs))
+		ofs = 29;
+
+	do {
+		for (i = 0; i < sc->lanes; i++) {
+			if (!LANE_ENABLE(sc, i))
+				continue;
+
+			/* no need to check again if this lane's status
+			 * is already good
+			 */
+			if (!(lanes_not_ok & (1 << i)))
+				continue;
+
+			ret = kserdes_readl(sc->regs, CML_REG(0x1f8));
+
+			/* clear corresponding lane_not_ok bit if
+			 * status is good (1)
+			 */
+			if (ret & BIT(ofs + i))
+				lanes_not_ok &= ~(1 << i);
+		}
+
+		/* get out if all lanes are good to go */
+		if (!lanes_not_ok)
+			return 0;
+
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+
+		cpu_relax();
+	} while (true);
+}
+
+static int kserdes_deassert_reset_poll_pcie(struct kserdes_config *sc)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(500);
+	u32 lanes_not_ok = 0;
+	u32 ret, i;
+
+	/* assume all enable lanes not-ok (1) and all others
+	 * ok (0) to start
+	 */
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		lanes_not_ok |= (1 << i);
+	}
+
+	do {
+		for (i = 0; i < sc->lanes; i++) {
+			if (!LANE_ENABLE(sc, i))
+				continue;
+
+			/* no need to check again if this lane's status
+			 * is already good
+			 */
+			if (!(lanes_not_ok & (1 << i)))
+				continue;
+
+			ret = _kserdes_read_select_tbus(sc->regs, i + 1, 0x02);
+
+			/* clear corresponding lane_not_ok bit if
+			 * status is good (0)
+			 */
+			if (!(ret & BIT(4)))
+				lanes_not_ok &= ~(1 << i);
+		}
+
+		/* get out if all lanes are good to go */
+		if (!lanes_not_ok)
+			return 0;
+
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+
+		cpu_relax();
+	} while (true);
+}
+
+static inline void _kserdes_lane_reset(void __iomem *serdes,
+				       u32 lane, u32 reset)
+{
+	if (reset)
+		FINSR(serdes, LANEX_REG(lane, 0x28), 29, 29, 0x1);
+	else
+		FINSR(serdes, LANEX_REG(lane, 0x28), 29, 29, 0x0);
+}
+
+static inline void kserdes_release_reset(struct kserdes_config *sc, u32 lane)
+{
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		/* set pma_cmu_sel to 1 */
+		FINSR(sc->regs, LANEX_REG(lane, 0x60), 0, 0, 0x1);
+	}
+	/* release reset */
+	_kserdes_lane_reset(sc->regs, lane, 0);
+}
+
+static int kserdes_deassert_reset(struct kserdes_config *sc, u32 poll)
+{
+	int ret = 0;
+
+	for_each_enable_lane(kserdes_release_reset, sc);
+
+	if (!poll)
+		goto done;
+
+	/* Check Lane OK */
+	if (sc->phy_type == KSERDES_PHY_PCIE)
+		ret = kserdes_deassert_reset_poll_pcie(sc);
+	else
+		ret = kserdes_deassert_reset_poll_others(sc);
+
+done:
+	return ret;
+}
+
+static inline void kserdes_lane_disable(struct kserdes_config *sc, u32 lane)
+{
+	FINSR(sc->regs, LANE_CTRL_STS_REG(lane), 31, 29, 0x4);
+	FINSR(sc->regs, LANE_CTRL_STS_REG(lane), 15, 13, 0x4);
+}
+
+static inline void _kserdes_lane_enable(void __iomem *sregs, u32 lane)
+{
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 31, 29, 0x7);
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 15, 13, 0x7);
+}
+
+/* Caller should make sure sgmii cannot be fullrate */
+static inline int _kserdes_set_lane_ctrl_rate(
+	void __iomem			*sregs,
+	u32				lane,
+	enum KSERDES_LANE_CTRL_RATE	lane_ctrl_rate)
+{
+	u32 rate_mode;
+
+	if (lane_ctrl_rate == KSERDES_FULL_RATE)
+		rate_mode = 0x4;
+	else if (lane_ctrl_rate == KSERDES_QUARTER_RATE)
+		rate_mode = 0x6;
+	else if (lane_ctrl_rate == KSERDES_HALF_RATE)
+		rate_mode = 0x5;
+	else
+		return -EINVAL;
+
+	/* Tx */
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 28, 26, rate_mode);
+	/* Rx */
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 12, 10, rate_mode);
+	return 0;
+}
+
+static inline void _kserdes_set_lane_loopback(
+	void __iomem			*sregs,
+	u32				lane,
+	enum KSERDES_LINK_RATE		link_rate)
+{
+	if (link_rate == KSERDES_LINK_RATE_10P3125G) {
+		FINSR(sregs, LANEX_REG(lane, 0x0), 7, 0, 0x4);
+		FINSR(sregs, LANEX_REG(lane, 0x4), 2, 1, 0x3);
+	} else {
+		FINSR(sregs, LANEX_REG(lane, 0x0), 31, 24, 0x40);
+	}
+}
+
+static void kserdes_set_lane_rate(struct kserdes_config *sc, u32 lane)
+{
+	int ret;
+
+	ret = _kserdes_set_lane_ctrl_rate(sc->regs, lane,
+					  sc->lane[lane].ctrl_rate);
+	if (ret) {
+		dev_err(sc->dev, "set_lane_rate FAILED: lane = %d err = %d\n",
+			lane, ret);
+		return;
+	}
+
+	/* disable attenuation auto scale */
+	FINSR(sc->regs, LANEX_REG(lane, 0x30), 11, 11, 0x1);
+	FINSR(sc->regs, LANEX_REG(lane, 0x30), 13, 12, 0x0);
+
+	/* set NES bit if loopback enabled */
+	if (sc->lane[lane].loopback)
+		_kserdes_set_lane_loopback(sc->regs, lane, sc->link_rate);
+
+	_kserdes_lane_enable(sc->regs, lane);
+}
+
+static inline void _kserdes_set_wait_after(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 17, 16, 0x3);
+}
+
+static inline void _kserdes_clear_wait_after(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 17, 16, 0);
+}
+
+static inline void _kserdes_pll_enable(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 31, 29, 0x7);
+}
+
+static inline void _kserdes_pll2_enable(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 27, 25, 0x7);
+}
+
+static inline void _kserdes_pll_disable(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 31, 29, 0x4);
+}
+
+static inline void _kserdes_pll2_disable(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 27, 25, 0x4);
+}
+
+static inline u32 _kserdes_get_pll_status(void __iomem *sregs)
+{
+	return FEXTR(kserdes_readl(sregs, PLL_CTRL_REG), 28, 28);
+}
+
+static inline u32 _kserdes_get_pll2_status(void __iomem *sregs)
+{
+	return FEXTR(kserdes_readl(sregs, PLL_CTRL_REG), 24, 24);
+}
+
+static inline void kserdes_lane_enable_loopback(void __iomem *serdes, u32 lane)
+{
+	FINSR(serdes, LANEX_REG(lane, 0), 31, 24, 0x40);
+}
+
+static inline u32 _kserdes_get_lane_status(
+		void __iomem		*sregs,
+		u32			lane,
+		enum KSERDES_PHY_TYPE	phy_type)
+{
+	if (phy_type == KSERDES_PHY_PCIE) {
+		return FEXTR(kserdes_readl(sregs, PLL_CTRL_REG), lane, lane);
+	} else if (phy_type == KSERDES_PHY_XGE) {
+		return FEXTR(kserdes_readl(sregs, CML_REG(0x1f8)),
+			     (29 + lane), (29 + lane));
+	} else {
+		return FEXTR(kserdes_readl(sregs, PLL_CTRL_REG),
+			     (8 + lane), (8 + lane));
+	}
+}
+
+static u32 kserdes_get_pll_lanes_status(struct kserdes_config *sc)
+{
+	u32 val, i;
+
+	/* Check PLL OK Status Bit */
+	val = _kserdes_get_pll_status(sc->regs);
+	if (!val) {
+		/* pll is not ready */
+		goto done;
+	}
+
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		val = _kserdes_get_pll2_status(sc->regs);
+		if (!val)
+			goto done;
+	}
+
+	/* Check Lane OK Status Bits */
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		val &= _kserdes_get_lane_status(sc->regs, i, sc->phy_type);
+	}
+
+done:
+	/* if any of the status is 0, this is 0
+	 * i.e. serdes status is not good
+	 */
+	return val;
+}
+
+int kserdes_get_status(struct kserdes_config *sc)
+{
+	unsigned long timeout;
+
+	/* is 500 msec a good number? */
+	timeout = jiffies + msecs_to_jiffies(500);
+	do {
+		if (kserdes_get_pll_lanes_status(sc))
+			break;
+
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+
+		cpu_relax();
+	} while (true);
+
+	return 0;
+}
+
+static inline u32 _kserdes_get_tx_termination(
+		void __iomem		*sregs,
+		enum KSERDES_PHY_TYPE	phy_type,
+		u32			lane)
+{
+	return (_kserdes_read_select_tbus(sregs, lane + 1,
+					  ((phy_type == KSERDES_PHY_XGE) ?
+					  0x1a : 0x1b)) & 0xff);
+}
+
+static void kserdes_set_tx_terminations(struct kserdes_config *sc, u32 term)
+{
+	u32 i;
+
+	for (i = 0; i < sc->lanes; i++) {
+		FINSR(sc->regs, LANEX_REG(i, 0x7c), 31, 24, term);
+		/* set termination override */
+		FINSR(sc->regs, LANEX_REG(i, 0x7c), 20, 20, 0x1);
+	}
+}
+
+/* lane is 0-based */
+static void
+_kserdes_get_cmp_tap_offsets_xge(void __iomem *sregs, u32 lane, u32 cmp,
+				 struct kserdes_comparator_tap_offsets *ofs)
+{
+	/* set comparator number */
+	FINSR(sregs, CML_REG(0x8c), 23, 21, cmp);
+
+	/* read offsets */
+	FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((lane + 2) << 8) + 0x11);
+	ofs->cmp = (_kserdes_read_tbus_val(sregs) & 0x0ff0) >> 4;
+
+	FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((lane + 2) << 8) + 0x11);
+	ofs->tap1 = (_kserdes_read_tbus_val(sregs) & 0x000f) << 3;
+
+	FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((lane + 2) << 8) + 0x12);
+	ofs->tap1 |= (_kserdes_read_tbus_val(sregs) & 0x0e00) >> 9;
+	ofs->tap2  = (_kserdes_read_tbus_val(sregs) & 0x01f8) >> 3;
+	ofs->tap3  = (_kserdes_read_tbus_val(sregs) & 0x0007) << 3;
+
+	FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((lane + 2) << 8) + 0x13);
+	ofs->tap3 |= (_kserdes_read_tbus_val(sregs) & 0x0e00) >> 9;
+	ofs->tap4  = (_kserdes_read_tbus_val(sregs) & 0x01f8) >> 3;
+	ofs->tap5  = (_kserdes_read_tbus_val(sregs) & 0x0007) << 3;
+
+	FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((lane + 2) << 8) + 0x14);
+	ofs->tap5 |= (_kserdes_read_tbus_val(sregs) & 0x0e00) >> 9;
+}
+
+static void kserdes_add_offsets_xge(struct kserdes_config *sc,
+				    struct kserdes_offsets *sofs)
+{
+	struct kserdes_comparator_tap_offsets *ctofs;
+	struct kserdes_comparator_tap_offsets sample;
+	struct kserdes_lane_offsets *lofs;
+	u32 lane, cmp;
+
+	for (lane = 0; lane < sc->lanes; lane++) {
+		lofs = &sofs->lane_ofs[lane];
+		/* yes cmp starts from 1 */
+		for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+			ctofs = &lofs->ct_ofs[cmp];
+
+			_kserdes_get_cmp_tap_offsets_xge(sc->regs, lane,
+							 cmp, &sample);
+
+			ctofs->cmp  += sample.cmp;
+			ctofs->tap1 += sample.tap1;
+			ctofs->tap2 += sample.tap2;
+			ctofs->tap3 += sample.tap3;
+			ctofs->tap4 += sample.tap4;
+			ctofs->tap5 += sample.tap5;
+		}
+	}
+}
+
+/* lane is 0-based */
+static void
+kserdes_get_cmp_tap_offsets_non_xge(void __iomem *sregs, u32 lane, u32 cmp,
+				    struct kserdes_comparator_tap_offsets *ofs)
+{
+	/* set comparator number */
+	FINSR(sregs, CML_REG(0x8c), 23, 21, cmp);
+
+	/* read offsets */
+	FINSR(sregs, CMU0_REG(0x8), 31, 24, ((lane + 1) << 5) + 0x12);
+	ofs->cmp = (_kserdes_read_tbus_val(sregs) & 0x0ff0) >> 4;
+}
+
+static void kserdes_add_offsets_non_xge(struct kserdes_config *sc,
+					struct kserdes_offsets *sofs)
+{
+	struct kserdes_comparator_tap_offsets *ctofs;
+	struct kserdes_comparator_tap_offsets sample;
+	struct kserdes_lane_offsets *lofs;
+	u32 lane, cmp;
+
+	for (lane = 0; lane < sc->lanes; lane++) {
+		lofs = &sofs->lane_ofs[lane];
+		/* yes cmp starts from 1 */
+		for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+			ctofs = &lofs->ct_ofs[cmp];
+
+			kserdes_get_cmp_tap_offsets_non_xge(sc->regs, lane,
+							    cmp, &sample);
+
+			ctofs->cmp  += sample.cmp;
+		}
+	}
+}
+
+static void kserdes_get_average_offsets(struct kserdes_config *sc, u32 samples,
+					struct kserdes_offsets *sofs)
+{
+	struct kserdes_comparator_tap_offsets *ctofs;
+	struct kserdes_lane_offsets *lofs;
+	u32 i, lane, cmp;
+	int ret;
+
+	memset(sofs, 0, sizeof(*sofs));
+
+	/* get the total of each offset for specified number of samples */
+	for (i = 0; i < samples; i++) {
+		kserdes_assert_reset(sc);
+		ret = kserdes_deassert_reset(sc, 1);
+		if (ret) {
+			dev_err(sc->dev,
+				"kserdes_get_average_offsets: reset failed %d\n",
+				ret);
+			return;
+		}
+
+		if (sc->phy_type == KSERDES_PHY_XGE)
+			kserdes_add_offsets_xge(sc, sofs);
+		else
+			kserdes_add_offsets_non_xge(sc, sofs);
+	}
+
+	/* take the average */
+	for (lane = 0; lane < sc->lanes; lane++) {
+		lofs = &sofs->lane_ofs[lane];
+		/* yes cmp starts from 1 */
+		for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+			ctofs = &lofs->ct_ofs[cmp];
+			if (sc->phy_type == KSERDES_PHY_XGE) {
+				ctofs->cmp  /= samples;
+				ctofs->tap1 /= samples;
+				ctofs->tap2 /= samples;
+				ctofs->tap3 /= samples;
+				ctofs->tap4 /= samples;
+				ctofs->tap5 /= samples;
+			} else {
+				ctofs->cmp  /= samples;
+			}
+		}
+	}
+}
+
+static void
+_kserdes_override_cmp_tap_offsets(void __iomem *sregs, u32 lane, u32 cmp,
+				  struct kserdes_comparator_tap_offsets *ofs)
+{
+	/* set dfe_shadow_lane_sel */
+	FINSR(sregs, CML_REG(0xf0), 27, 26, (lane + 1));
+
+	/* set cmp_offset_ovr_en to 1 */
+	FINSR(sregs, CML_REG(0x98), 24, 24, 0x1);
+
+	/* set rxeq_ovr_en to 0x1 */
+	FINSR(sregs, LANEX_REG(lane, 0x2c), 2, 2, 0x1);
+
+	/* set rxeq_dfe_cmp_sel_ovr to comp_no */
+	FINSR(sregs, LANEX_REG(lane, 0x30), 7, 5, cmp);
+
+	/* set dfe_tap_ovr_en to 1 */
+	FINSR(sregs, LANEX_REG(lane, 0x5c), 31, 31, 0x1);
+
+	/* set cmp offset override */
+	FINSR(sregs, CML_REG(0x9c), 7, 0, ofs->cmp);
+	/* set tap offset overrides */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 30, 24, ofs->tap1);
+	FINSR(sregs, LANEX_REG(lane, 0x5c),  5,  0, ofs->tap2);
+	FINSR(sregs, LANEX_REG(lane, 0x5c), 13,  8, ofs->tap3);
+	FINSR(sregs, LANEX_REG(lane, 0x5c), 21, 16, ofs->tap4);
+	FINSR(sregs, LANEX_REG(lane, 0x5c), 29, 24, ofs->tap5);
+
+	/* set rxeq_ovr_latch_o = 0x1 */
+	FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x1);
+	/* set rxeq_ovr_latch_o = 0x0 */
+	FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x0);
+
+	/* set cmp_offset_ovr_en to 0 */
+	FINSR(sregs, CML_REG(0x98), 24, 24, 0x0);
+	/* set rxeq_ovr_en to 0x0 */
+	FINSR(sregs, LANEX_REG(lane, 0x2c), 2, 2, 0x0);
+	/* set dfe_tap_ovr_en to 0 */
+	FINSR(sregs, LANEX_REG(lane, 0x5c), 31, 31, 0x0);
+}
+
+static inline void
+_kserdes_override_cmp_offset_cdfe(void __iomem *sregs, u32 lane,
+				  u32 cmp, u32 cmp_offset)
+{
+	/* enable comparator offset calibrate */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 18, 18, 0x1);
+
+	/* set gcfsm sel override to comparator */
+	FINSR(sregs, LANEX_REG(lane, 0x4c), 5, 2, (0x1 << (cmp - 1)));
+	/* set comparator offset */
+	FINSR(sregs, LANEX_REG(lane, 0x48), 24, 17, cmp_offset);
+	/* latch in value */
+	FINSR(sregs, LANEX_REG(lane, 0x48), 29, 29, 0x1);
+	FINSR(sregs, LANEX_REG(lane, 0x48), 29, 29, 0x0);
+
+	/* disable comparator offset calibrate */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 18, 18, 0x0);
+}
+
+static inline void
+_kserdes_override_tap_offset_cdfe(void __iomem *sregs, u32 lane,
+				  u32 tap, u32 width, u32 tap_offset)
+{
+	/* enable tap */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 23, 19, BIT(tap - 1));
+	/* set tap offset */
+	FINSR(sregs, LANEX_REG(lane, 0x48), 17 + (width - 1), 17, tap_offset);
+	/* latch in value */
+	FINSR(sregs, LANEX_REG(lane, 0x48), 29, 29, 0x1);
+	FINSR(sregs, LANEX_REG(lane, 0x48), 29, 29, 0x0);
+}
+
+static void _kserdes_override_cmp_tap_offsets_cdfe(
+	void __iomem				*sregs,
+	u32					lane,
+	u32					cmp,
+	struct kserdes_comparator_tap_offsets	*ofs)
+{
+	/* enable overrides */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 16, 16, 0x1);
+	FINSR(sregs, LANEX_REG(lane, 0x48), 16, 16, 0x1);
+
+	_kserdes_override_cmp_offset_cdfe(sregs, lane, cmp, ofs->cmp);
+
+	/* enable tap offset calibrate */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 17, 17, 0x1);
+
+	/* set tap offsets */
+	_kserdes_override_tap_offset_cdfe(sregs, lane, 1, 7, ofs->tap1);
+	_kserdes_override_tap_offset_cdfe(sregs, lane, 2, 6, ofs->tap2);
+	_kserdes_override_tap_offset_cdfe(sregs, lane, 3, 6, ofs->tap3);
+	_kserdes_override_tap_offset_cdfe(sregs, lane, 4, 6, ofs->tap4);
+	_kserdes_override_tap_offset_cdfe(sregs, lane, 5, 6, ofs->tap5);
+
+	/* disable overrides */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 16, 16, 0x0);
+	FINSR(sregs, LANEX_REG(lane, 0x48), 16, 16, 0x0);
+	FINSR(sregs, LANEX_REG(lane, 0x58), 18, 18, 0x0);
+	FINSR(sregs, LANEX_REG(lane, 0x58), 17, 17, 0x0);
+}
+
+static void kserdes_set_offsets_xge(struct kserdes_config *sc,
+				    struct kserdes_offsets *sofs)
+{
+	struct kserdes_comparator_tap_offsets *ctofs;
+	struct kserdes_lane_offsets *lofs;
+	u32 lane, cmp;
+
+	for (lane = 0; lane < sc->lanes; lane++) {
+		lofs = &sofs->lane_ofs[lane];
+		for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+			ctofs = &lofs->ct_ofs[cmp];
+			_kserdes_override_cmp_tap_offsets(sc->regs, lane,
+							  cmp, ctofs);
+			_kserdes_override_cmp_tap_offsets_cdfe(sc->regs, lane,
+							       cmp, ctofs);
+		}
+	}
+}
+
+static void kserdes_set_offsets_non_xge(struct kserdes_config *sc,
+					struct kserdes_offsets *sofs)
+{
+	struct kserdes_comparator_tap_offsets *ctofs;
+	struct kserdes_lane_offsets *lofs;
+	u32 lane, cmp;
+
+	for (lane = 0; lane < sc->lanes; lane++) {
+		lofs = &sofs->lane_ofs[lane];
+		for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+			ctofs = &lofs->ct_ofs[cmp];
+			_kserdes_override_cmp_tap_offsets(sc->regs, lane,
+							  cmp, ctofs);
+		}
+	}
+}
+
+static void kserdes_set_offsets(struct kserdes_config *sc,
+				struct kserdes_offsets *sofs)
+{
+	if (sc->phy_type == KSERDES_PHY_XGE)
+		kserdes_set_offsets_xge(sc, sofs);
+	else
+		kserdes_set_offsets_non_xge(sc, sofs);
+}
+
+static void kserdes_dfe_offset_calibration(struct kserdes_config *sc,
+					   struct kserdes_offsets *sofs)
+{
+	for_each_enable_lane(kserdes_force_signal_detect_low, sc);
+	usleep_range(10, 20);
+
+	/* offset compensation patch */
+	kserdes_get_average_offsets(sc, DFE_OFFSET_SAMPLES, sofs);
+	kserdes_set_offsets(sc, sofs);
+	usleep_range(10, 20);
+
+	/* re-acquire signal detect */
+	for_each_lane(kserdes_force_signal_detect_high, sc);
+	usleep_range(10, 20);
+}
+
+static void kserdes_override_tap_offsets(struct kserdes_config *sc, u32 lane)
+{
+	u32 tap1val, tap2val, tap3val, tap4val, tap5val;
+	void __iomem *sregs = sc->regs;
+	u32 cmp, tap1_ofs;
+
+	for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+		/* adjust taps only for center comparators of
+		 * of conparator 1 and 3
+		 */
+		if (!(cmp & 0x1))
+			continue;
+
+		/* set comparator number */
+		FINSR(sregs, CML_REG(0x8c), 23, 21, cmp);
+
+		/* read offsets */
+		FINSR(sregs, CMU0_REG(0x8), 31, 24, ((lane + 1) << 5) + 0x12);
+		tap1_ofs = (_kserdes_read_tbus_val(sregs) & 0x000f) << 3;
+
+		FINSR(sregs, CMU0_REG(0x8), 31, 24, ((lane + 1) << 5) + 0x13);
+		tap1_ofs |= (_kserdes_read_tbus_val(sregs) & 0x0e00) >> 9;
+
+		tap1val = tap1_ofs - 14;
+		tap2val = 31;
+		tap3val = 31;
+		tap4val = 31;
+		tap5val = 31;
+
+		/* set dfe_shadow_lane_sel */
+		FINSR(sregs, CML_REG(0xf0), 27, 26, lane + 1);
+		/* Set rxeq_ovr_en to 0x1 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 2, 2, 0x1);
+		/* set rxeq_dfe_cmp_sel_ovr to comp_no */
+		FINSR(sregs, LANEX_REG(lane, 0x30), 7, 5, cmp);
+		/* set dfe_tap_ovr_en to 1 */
+		FINSR(sregs, LANEX_REG(lane, 0x5c), 31, 31, 0x1);
+
+		/* set tap overrides */
+		FINSR(sregs, LANEX_REG(lane, 0x58), 30, 24, tap1val);
+		FINSR(sregs, LANEX_REG(lane, 0x5c),  6,  0, tap2val);
+		FINSR(sregs, LANEX_REG(lane, 0x5c), 13,  8, tap3val);
+		FINSR(sregs, LANEX_REG(lane, 0x5c), 21, 16, tap4val);
+		FINSR(sregs, LANEX_REG(lane, 0x5c), 29, 24, tap5val);
+
+		/* set rxeq_ovr_latch_o = 0x1 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x1);
+		/* set rxeq_ovr_latch_o = 0x0 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x0);
+
+		/* set rxeq_ovr_en to 0 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 2, 2, 0x0);
+		/* set dfe_tap_ovr_en to 0 */
+		FINSR(sregs, LANEX_REG(lane, 0x5c), 31, 31, 0x0);
+
+		/* This part of code will latch in offsets to
+		 * tap adaptation logic so that if adaptation
+		 * occurs, it will pick these offsets
+		 */
+		/* enable overrides */
+		FINSR(sregs, LANEX_REG(lane, 0x58), 16, 16, 0x1);
+		FINSR(sregs, LANEX_REG(lane, 0x48), 16, 16, 0x1);
+
+		/* set gcfsm_cmp_sel to comp_no */
+		FINSR(sregs, LANEX_REG(lane, 0x4c), 5, 2, (0x1 << (cmp - 1)));
+		/* enable tap offset calibrate */
+		FINSR(sregs, LANEX_REG(lane, 0x58), 17, 17, 0x1);
+
+		/* enable taps */
+		_kserdes_override_tap_offset_cdfe(sregs, lane, 1, 7, tap1val);
+		_kserdes_override_tap_offset_cdfe(sregs, lane, 2, 6, tap2val);
+		_kserdes_override_tap_offset_cdfe(sregs, lane, 3, 6, tap3val);
+		_kserdes_override_tap_offset_cdfe(sregs, lane, 4, 6, tap4val);
+		_kserdes_override_tap_offset_cdfe(sregs, lane, 5, 6, tap5val);
+
+		/* Disable overrides */
+		FINSR(sregs, LANEX_REG(lane, 0x58), 16, 16, 0x0);
+		FINSR(sregs, LANEX_REG(lane, 0x48), 16, 16, 0x0);
+		FINSR(sregs, LANEX_REG(lane, 0x58), 17, 17, 0x0);
+	}
+}
+
+static int kserdes_wait_lane_rx_valid(struct kserdes_config *sc, u32 lane)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(500);
+	u32 status;
+
+	do {
+		status = _kserdes_read_select_tbus(sc->regs, lane + 1, 0x02);
+
+		if (status & 0x20)
+			return 0;
+
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+
+		cpu_relax();
+	} while (true);
+}
+
+static int kserdes_att_boost_phya_macro_patch(struct kserdes_config *sc)
+{
+	u32 i, att_read[KSERDES_MAX_LANES], att_start[KSERDES_MAX_LANES];
+	int ret;
+
+	/* First save a copy of initial att start value */
+	for (i = 0; i < sc->lanes; i++) {
+		att_start[i] = kserdes_readl(sc->regs, LANEX_REG(i, 0x8c));
+		att_start[i] = (att_start[i] >> 8) & 0xf;
+	}
+	/* Get att and fix this as start value.  Turn off att adaptation and
+	 * do boost readaptation
+	 */
+	for (i = 0; i < sc->lanes; i++) {
+		att_read[i] = _kserdes_read_select_tbus(
+					sc->regs, i + 1,
+					(sc->phy_type == KSERDES_PHY_XGE) ?
+					0x10 : 0x11);
+		att_read[i] = (att_read[i] >> 4) & 0xf;
+	}
+	for (i = 0; i < sc->lanes; i++) {
+		/* att start */
+		FINSR(sc->regs, LANEX_REG(i, 0x8c), 11, 8, att_read[i]);
+	}
+	/* clear att init calibration */
+	FINSR(sc->regs, CML_REG(0x84), 0, 0, 0x0);
+	/* clear att re-calibration */
+	FINSR(sc->regs, CML_REG(0x8c), 24, 24, 0x0);
+
+	/* force calibration on all lanes */
+	/* set att continuous recal */
+	FINSR(sc->regs, CML_REG(0x98), 7, 7, 0x1);
+	/* clear att continuous recal */
+	FINSR(sc->regs, CML_REG(0x98), 7, 7, 0x0);
+	usleep_range(300, 400);
+
+	/* check rx valid */
+	for_each_enable_lane_return(kserdes_wait_lane_rx_valid, sc, ret);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_wait_lane_rx_valid FAILED %d\n", ret);
+		return ret;
+	}
+
+	/* write back initial att start value */
+	for (i = 0; i < sc->lanes; i++)
+		FINSR(sc->regs, LANEX_REG(i, 0x8c), 11, 8, att_start[i]);
+
+	/* turn att adaptation back on */
+	FINSR(sc->regs, CML_REG(0x84),  0,  0, 0x1);
+	FINSR(sc->regs, CML_REG(0x8c), 24, 24, 0x1);
+
+	return 0;
+}
+
+static int kserdes_att_boost_phya_lane_patch(struct kserdes_config *sc,
+					     u32 lane)
+{
+	u32 boost_read;
+	int ret;
+
+	/* check lane rx valid */
+	ret = kserdes_wait_lane_rx_valid(sc, lane);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_wait_lane_rx_valid FAILED %d\n", ret);
+		return ret;
+	}
+
+	/* check boost value */
+	boost_read = _kserdes_read_select_tbus(
+				sc->regs, lane + 1,
+				(sc->phy_type == KSERDES_PHY_XGE) ?
+				0x10 : 0x11);
+	boost_read = (boost_read >> 8) & 0xf;
+
+	/* increment boost by 1 if it's 0 */
+	if (!boost_read) {
+		/* Set rxeq_ovr_en to 1 */
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c),  2,  2, 0x1);
+		/* set rxeq_ovr_load_en for boost only */
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c), 18, 12, 0x2);
+		/* set rxeq_ovr_load for a value of 1 */
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c),  9,  3, 0x1);
+		/* latch in new boost value */
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c), 10, 10, 0x1);
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c), 10, 10, 0x0);
+		/* reset previous registers */
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c),  2,  2, 0x0);
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c), 18, 12, 0x0);
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c),  9,  3, 0x0);
+	}
+	return 0;
+}
+
+static inline void kserdes_att_boost_phya_patch(struct kserdes_config *sc)
+{
+	kserdes_att_boost_phya_macro_patch(sc);
+
+	for_each_enable_lane(kserdes_att_boost_phya_lane_patch, sc);
+}
+
+static void kserdes_att_boost_phyb_lane_patch(struct kserdes_config *sc,
+					      u32 lane)
+{
+	u32 tbus_ofs, rxeq_init_reg_ofs, rxeq_ln_reg_ofs, rxeq_ln_force_bit;
+	void __iomem *sregs = sc->regs;
+	u32 att_start, att_read, boost_read;
+	int ret;
+
+	/* some setups */
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		tbus_ofs = 0x10;
+		rxeq_init_reg_ofs = 0x9c;
+		rxeq_ln_reg_ofs = 0x98;
+		rxeq_ln_force_bit = 14;
+	} else {
+		tbus_ofs = 0x11;
+		rxeq_init_reg_ofs = 0x84;
+		rxeq_ln_reg_ofs = 0xac;
+		rxeq_ln_force_bit = 11;
+	}
+
+	/* First save a copy of initial att start value */
+	att_start = kserdes_readl(sregs, LANEX_REG(lane, 0x8c));
+	att_start = (att_start >> 8) & 0xf;
+
+	/* Get att and fix this as start value.  Turn off att adaptation and
+	 * do boost readaptation
+	 */
+	att_read = _kserdes_read_select_tbus(sregs, lane + 1, tbus_ofs);
+	att_read = (att_read >> 4) & 0xf;
+
+	/* att start */
+	FINSR(sregs, LANEX_REG(lane, 0x8c), 11, 8, att_read);
+	/* clear att init calibration */
+	FINSR(sregs, LANEX_REG(lane, rxeq_init_reg_ofs), 0, 0, 0x0);
+	/* clear att re-calibration */
+	FINSR(sregs, CML_REG(0x8c), 24, 24, 0x0);
+
+	/* force calibration */
+	FINSR(sregs, LANEX_REG(lane, rxeq_ln_reg_ofs),
+	      rxeq_ln_force_bit, rxeq_ln_force_bit, 0x1);
+	FINSR(sregs, LANEX_REG(lane, rxeq_ln_reg_ofs),
+	      rxeq_ln_force_bit, rxeq_ln_force_bit, 0x0);
+
+	/* check lane rx valid */
+	ret = kserdes_wait_lane_rx_valid(sc, lane);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_wait_lane_rx_valid %d FAILED: %d\n",
+			lane, ret);
+	}
+	usleep_range(300, 400);
+
+	/* check boost value */
+	boost_read = _kserdes_read_select_tbus(sregs, lane + 1, tbus_ofs);
+	boost_read = (boost_read >> 8) & 0xf;
+
+	/* increment boost by 1 if it's 0 */
+	if (!boost_read) {
+		/* Set rxeq_ovr_en to 1 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c),  2,  2, 0x1);
+		/* set rxeq_ovr_load_en for boost only */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 18, 12, 0x2);
+		/* set rxeq_ovr_load for a value of 1 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c),  9,  3, 0x1);
+		/* latch in new boost value */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x1);
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x0);
+		/* reset previous registers */
+		FINSR(sregs, LANEX_REG(lane, 0x2c),  2,  2, 0x0);
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 18, 12, 0x0);
+		FINSR(sregs, LANEX_REG(lane, 0x2c),  9,  3, 0x0);
+	}
+
+	/* write back initial att start value */
+	FINSR(sregs, LANEX_REG(lane, 0x8c), 11, 8, att_start);
+	/* turn att adaptation back on */
+	FINSR(sregs, LANEX_REG(lane, rxeq_init_reg_ofs), 0, 0, 0x1);
+	FINSR(sregs, CML_REG(0x8c), 24, 24, 0x1);
+}
+
+static inline void kserdes_att_boost_phyb_patch(struct kserdes_config *sc,
+						u32 lane)
+{
+	kserdes_att_boost_phyb_lane_patch(sc, lane);
+}
+
+static void kserdes_att_boost_phy_patch(struct kserdes_config *sc)
+{
+	if (sc->phy_type != KSERDES_PHY_XGE)
+		kserdes_att_boost_phya_patch(sc);
+	else
+		for_each_lane(kserdes_att_boost_phyb_patch, sc);
+}
+
+int kserdes_sgmii_lanes_enable(struct kserdes_config *sc)
+{
+	int ret, i;
+	u32 val, lanes_enable = 0;
+
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		lanes_enable |= (1 << i);
+	}
+
+	/* configure Tap 1 if PHY-A and link rate greater than 8Gbaud */
+	if (sc->link_rate >= KSERDES_LINK_RATE_9P8304G)
+		kserdes_tap1_patch(sc);
+
+	/* disable transmitter on all lanes to prevent
+	 * receiver from adapting
+	 */
+	for_each_lane(kserdes_set_tx_idle, sc);
+
+	/* apply patch for link rates greater than 8Gbaud */
+	kserdes_phy_patch(sc);
+
+	/* write boost training pattern for Hyperlink functional mode */
+	if (sc->phy_type == KSERDES_PHY_HYPERLINK)
+		_kserdes_set_training_pattern(sc->regs);
+
+	/* assert serdes reset */
+	kserdes_assert_reset(sc);
+
+	/* apply the TX and RX FIR coefficients to the lanes */
+	for_each_enable_lane(kserdes_set_tx_rx_fir_coeff, sc);
+
+	/* force Signal Detect Low. This resets the CDR,
+	 * Attenuation and Boost circuitry
+	 */
+	for_each_enable_lane(kserdes_force_signal_detect_low, sc);
+
+	ret = kserdes_deassert_reset(sc, 0);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_deassert_reset FAILED %d\n", ret);
+		return ret;
+	}
+
+	/* allow signal detect enable */
+	for_each_enable_lane(kserdes_set_lane_rate, sc);
+
+	_kserdes_pll_enable(sc->regs);
+
+	ret = kserdes_get_status(sc);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_get_status FAILED %d\n", ret);
+		return ret;
+	}
+
+	/* get tx termination on lane 0 */
+	val = _kserdes_get_tx_termination(sc->regs, sc->phy_type, 0);
+
+	/* apply tx termination to all lanes */
+	kserdes_set_tx_terminations(sc, val);
+
+	if (sc->link_rate >= KSERDES_LINK_RATE_9P8304G) {
+		/* manually adjust Tap 1 value for phy-a > 8GBaud */
+		for_each_enable_lane(kserdes_override_tap_offsets, sc);
+	}
+
+	/* We are always in FUNCTIONAL mode, so we always
+	 * continue to the following.
+	 */
+	/* enable transmitter on all lanes */
+	for_each_enable_lane(kserdes_clr_tx_idle, sc);
+
+	/* allow Signal Detect Enable */
+	for_each_enable_lane(kserdes_force_signal_detect_high, sc);
+
+	/* Wait for RX Valid on all lanes */
+	for_each_enable_lane_return(kserdes_wait_lane_rx_valid, sc, ret);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_wait_lane_rx_valid FAILED %d\n", ret);
+		return ret;
+	}
+
+	/* Apply Attenuation and Boost Patch if rx force
+	 * flag is set
+	 */
+	if (!sc->rx_force_enable)
+		kserdes_att_boost_phy_patch(sc);
+
+	/* If needed, check for errors or see if DLPF is
+	 * railing and toggle signal detect
+	 */
+	/* CSL_Serdes_CDR_Reset(); */
+
+	/* Enable MAC RX to allow MAC to take control */
+	_kserdes_clear_wait_after(sc->regs);
+
+	return lanes_enable;
+}
+
+static int kserdes_sgmii_init(struct kserdes_config *sc)
+{
+	return kserdes_load_init_fw(sc, ks2_gbe_serdes_firmwares,
+				    ARRAY_SIZE(ks2_gbe_serdes_firmwares));
+}
+
+static inline void _kserdes_set_link_loss_wait(void __iomem *sregs,
+					       u32 link_loss_wait)
+{
+	kserdes_writel(sregs, LINK_LOSS_WAIT_REG, link_loss_wait);
+}
+
+static inline void _kserdes_reset(void __iomem *sregs)
+{
+	/* Toggle POR_EN bit */
+	FINSR(sregs, CPU_CTRL_REG, 29, 29, 0x1);
+	usleep_range(10, 20);
+	FINSR(sregs, CPU_CTRL_REG, 29, 29, 0x0);
+	usleep_range(10, 20);
+}
+
+static inline void kserdes_xge_pll_enable(struct kserdes_config *sc)
+{
+	/* phyb reset clear */
+	if (!sc->firmware)
+		FINSR(sc->regs, CML_REG(0), 7, 0, 0x1f);
+
+	if (sc->link_rate == KSERDES_LINK_RATE_10P3125G) {
+		_kserdes_pll_enable(sc->regs);
+		_kserdes_pll2_enable(sc->regs);
+	} else if (sc->link_rate == KSERDES_LINK_RATE_1P25G) {
+		kserdes_writel(sc->regs, PLL_CTRL_REG, 0xe0000000);
+	}
+}
+
+static inline void _kserdes_xge_enable_pcs(void __iomem *sregs, u32 lane)
+{
+	/* set bus-width to 16 bit mode */
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 23, 21, 0x7);
+	FINSR(sregs, LANE_CTRL_STS_REG(lane),  5,  3, 0x7);
+
+	/* enable PCS overlay and lane select 10GKR */
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 16, 16, 0x1);
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 19, 19, 0x1);
+}
+
+static inline void kserdes_xge_lane_enable(struct kserdes_config *sc, u32 lane)
+{
+	u32 lane_ctrl_rate = sc->lane[lane].ctrl_rate;
+
+	/* Set Lane Control Rate */
+	if (sc->link_rate == KSERDES_LINK_RATE_10P3125G)
+		_kserdes_set_lane_ctrl_rate(sc->regs, lane, lane_ctrl_rate);
+	else if (sc->link_rate == KSERDES_LINK_RATE_1P25G)
+		kserdes_writel(sc->regs, LANE_CTRL_STS_REG(lane), 0xf800f8c0);
+
+	_kserdes_xge_enable_pcs(sc->regs, lane);
+
+	_kserdes_lane_enable(sc->regs, lane);
+
+	if (sc->lane[lane].loopback)
+		_kserdes_set_lane_loopback(sc->regs, lane, sc->link_rate);
+}
+
+static inline void _kserdes_enable_xgmii_port(struct regmap *peripheral_regmap,
+					      u32 port)
+{
+	regmap_update_bits(peripheral_regmap, XGE_CTRL_OFFSET,
+			   GENMASK(port, port), BIT(port));
+}
+
+static inline void _kserdes_reset_cdr(void __iomem *sregs, int lane)
+{
+	/* toggle signal detect */
+	_kserdes_force_signal_detect_low(sregs, lane);
+	mdelay(1);
+	_kserdes_force_signal_detect_high(sregs, lane);
+}
+
+/* Call every 10 ms */
+static int
+_kserdes_check_link_status(struct device *dev, void __iomem *sregs,
+			   struct regmap *pcsr_regmap, u32 lanes,
+			   u32 lanes_enable, u32 *current_state, u32 *lane_down)
+{
+	u32 pcsr_rx_stat, blk_lock, blk_errs;
+	int loss, i, status = 1;
+	int ret;
+
+	for (i = 0; i < lanes; i++) {
+		if (!(lanes_enable & (1 << i)))
+			continue;
+
+		/* Rx Signal Loss bit in serdes lane control and status reg*/
+		loss = (kserdes_readl(sregs, LANE_CTRL_STS_REG(i))) & 0x01;
+
+		/* Block Errors and Block Lock bits in PCSR rx status reg */
+		ret = regmap_read(pcsr_regmap, PCSR_RX_STATUS(i),
+				  &pcsr_rx_stat);
+
+		if (ret)
+			return ret;
+
+		blk_lock = (pcsr_rx_stat >> 30) & 0x1;
+		blk_errs = (pcsr_rx_stat >> 16) & 0x0ff;
+
+		/* If Block error, attempt recovery! */
+		if (blk_errs)
+			blk_lock = 0;
+
+		switch (current_state[i]) {
+		case 0:
+			/* if good link lock the signal detect ON! */
+			if (!loss && blk_lock) {
+				dev_dbg(dev, "XGE PCSR Linked Lane: %d\n", i);
+				FINSR(sregs, LANEX_REG(i, 0x04), 2, 1, 0x3);
+				current_state[i] = 1;
+			} else {
+				/* if no lock, then reset CDR
+				 * by toggling sig detect
+				 */
+				if (!blk_lock) {
+					dev_dbg(dev,
+						"XGE PCSR Recover Lane: %d\n",
+						i);
+
+					_kserdes_reset_cdr(sregs, i);
+				}
+			}
+			break;
+		case 1:
+			if (!blk_lock) {
+				/* Link Lost? */
+				lane_down[i] = 1;
+				current_state[i] = 2;
+			}
+			break;
+		case 2:
+			if (blk_lock)
+				/* Nope just noise */
+				current_state[i] = 1;
+			else {
+				/* Lost the block lock, reset CDR if it is
+				 * not centered and go back to sync state
+				 */
+				_kserdes_reset_cdr(sregs, i);
+
+				current_state[i] = 0;
+			}
+			break;
+		default:
+			dev_info(dev, "XGE: unknown current_state[%d] %d\n",
+				 i, current_state[i]);
+			break;
+		}
+
+		if (blk_errs) {
+			/* Reset the Error counts! */
+			regmap_update_bits(pcsr_regmap, PCSR_RX_CTL(i),
+					   GENMASK(7, 0), 0x19);
+			regmap_update_bits(pcsr_regmap, PCSR_RX_CTL(i),
+					   GENMASK(7, 0), 0x00);
+		}
+
+		status &= (current_state[i] == 1);
+	}
+
+	return status;
+}
+
+static int _kserdes_wait_link_up(struct device *dev, void __iomem *sregs,
+				 struct regmap *pcsr_regmap,
+				 u32 lanes, u32 lanes_enable)
+{
+	u32 current_state[KSERDES_MAX_LANES];
+	int retries = 0, link_up;
+	u32 lane_down[KSERDES_MAX_LANES];
+	int i;
+
+	if (lanes > KSERDES_MAX_LANES)
+		return -EINVAL;
+
+	memset(current_state, 0, sizeof(current_state));
+	memset(lane_down, 0, sizeof(lane_down));
+
+	do {
+		mdelay(10);
+		memset(lane_down, 0, sizeof(lane_down));
+
+		link_up = _kserdes_check_link_status(dev, sregs,
+						     pcsr_regmap, lanes,
+						     lanes_enable,
+						     current_state, lane_down);
+
+		/* if we did not get link up then wait 100ms
+		 * before calling it again
+		 */
+		if (link_up)
+			break;
+
+		for (i = 0; i < lanes; i++) {
+			if ((lanes_enable & (1 << i)) && lane_down[i])
+				dev_dbg(dev,
+					"XGE: detected lane down on lane %d\n",
+					i);
+		}
+
+		if (++retries > 100)
+			return -ETIMEDOUT;
+
+	} while (!link_up);
+
+	dev_info(dev, "XGE: serdes link up: retried %d times\n", retries);
+	return 0;
+}
+
+static int kserdes_xge_lanes_enable(struct kserdes_config *sc)
+{
+	struct kserdes_offsets sofs;
+	int ret, i;
+	u32 lanes_enable = 0;
+
+	if (sc->firmware) {
+		/* firmware started in serdes_init and
+		 * doesn't need lanes enable
+		 */
+		return 0;
+	}
+
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		lanes_enable |= (1 << i);
+	}
+
+	kserdes_phy_patch(sc);
+	kserdes_xge_pll_enable(sc);
+
+	for_each_lane(kserdes_xge_lane_enable, sc);
+
+	ret = kserdes_get_status(sc);
+	if (ret) {
+		dev_err(sc->dev,
+			"kserdes_xge_lanes_enable get status FAILED %d\n", ret);
+		return ret;
+	}
+
+	kserdes_dfe_offset_calibration(sc, &sofs);
+
+	for (i = 0; i < sc->lanes; i++)
+		_kserdes_enable_xgmii_port(sc->peripheral_regmap, i);
+
+	_kserdes_wait_link_up(sc->dev, sc->regs, sc->pcsr_regmap,
+			      sc->lanes, lanes_enable);
+
+	return lanes_enable;
+}
+
+static inline void kserdes_xfw_get_lane_params(struct kserdes_config *sc,
+					       int lane)
+{
+	struct kserdes_fw_config *fw = &sc->fw;
+	u32 tx_ctrl, val_0, val_1;
+	u32 phy_a = PHY_A(sc->regs);
+
+	val_0 = kserdes_readl(sc->regs, LANEX_REG(lane, 0x04));
+	val_1 = kserdes_readl(sc->regs, LANEX_REG(lane, 0x08));
+
+	tx_ctrl = ((((val_0 >> 18) & 0x1)    << 24) |	/* TX_CTRL_O_24 */
+		   (((val_1 >> 0)  & 0xffff) <<  8) |	/* TX_CTRL_O_23_8 */
+		   (((val_0 >> 24) & 0xff)   <<  0));	/* TX_CTRL_O_7_0 */
+
+	if (phy_a) {
+		fw->cm = (val_1 >> 12) & 0xf;
+		fw->c1 = (val_1 >> 0) & 0x1f;
+		fw->c2 = (val_1 >> 8) & 0xf;
+	} else {
+		fw->cm = (tx_ctrl >> 16) & 0xf;
+		fw->c1 = (tx_ctrl >> 8) & 0x1f;
+		fw->c2 = (tx_ctrl >> 13) & 0x7;
+		fw->c2 = fw->c2 | (((tx_ctrl >> 24) & 0x1) << 3);
+	}
+
+	val_0 = _kserdes_read_select_tbus(sc->regs, lane + 1,
+					  (phy_a ? 0x11 : 0x10));
+	fw->attn = (val_0 >> 4) & 0xf;
+	fw->boost = (val_0 >> 8) & 0xf;
+
+	val_0 = _kserdes_read_select_tbus(sc->regs, lane + 1, 0x5);
+	fw->dlpf = (val_0 >> 2) & 0x3ff;
+
+	val_0 = _kserdes_read_select_tbus(sc->regs, lane + 1, 0x6);
+	fw->cdrcal = (val_0 >> 3) & 0xff;
+}
+
+static inline void kserdes_xfw_mem_init(struct kserdes_config *sc)
+{
+	struct kserdes_fw_config *fw = &sc->fw;
+	u32 i, lane_config = 0, lanes = sc->lanes;
+
+	for (i = 0; i < lanes; i++)
+		lane_config = (lane_config << 8) |
+			(fw->lane_config[i] & 0xff);
+
+	lane_config <<= 8;
+
+	/* initialize internal parameter area */
+	kserdes_writel(sc->regs, MEM_ADR_REG, KSERDES_XFW_CONFIG_START_ADDR);
+
+	/* clean out unused config area */
+	for (i = KSERDES_XFW_CONFIG_START_ADDR;
+	     i < KSERDES_XFW_PARAM_START_ADDR; i += 4)
+		kserdes_writel(sc->regs, MEM_DATINC_REG, 0x00000000);
+
+	/* Flush 64 bytes 10,11,12,13 */
+	kserdes_writel(sc->regs, MEM_DATINC_REG, 0x00009C9C);
+
+	/* fast train */
+	kserdes_writel(sc->regs, MEM_DATINC_REG, fw->fast_train);
+
+	kserdes_writel(sc->regs, MEM_DATINC_REG, 0x00000000);
+	/* lane seeds */
+	kserdes_writel(sc->regs, MEM_DATINC_REG, fw->lane_seeds);
+	/* lane config */
+	kserdes_writel(sc->regs, MEM_DATINC_REG, lane_config);
+}
+
+static int kserdes_xge_init(struct kserdes_config *sc)
+{
+	return kserdes_load_init_fw(sc, ks2_xgbe_serdes_firmwares,
+				    ARRAY_SIZE(ks2_xgbe_serdes_firmwares));
+}
+
+static int kserdes_pcie_lanes_enable(struct kserdes_config *sc)
+{
+	int ret, i;
+	u32 lanes_enable = 0;
+
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		lanes_enable |= (1 << i);
+	}
+
+	for (i = 0; i < sc->lanes; i++) {
+		kserdes_release_reset(sc, i);
+
+		if (sc->lane[i].loopback)
+			_kserdes_set_lane_loopback(sc->regs, i, sc->link_rate);
+	}
+
+	ret = kserdes_get_status(sc);
+	if (ret)
+		return ret;
+	else
+		return lanes_enable;
+}
+
+static int kserdes_pcie_init(struct kserdes_config *sc)
+{
+	return kserdes_load_init_fw(sc, ks2_pcie_serdes_firmwares,
+				    ARRAY_SIZE(ks2_pcie_serdes_firmwares));
+}
+
+static int kserdes_lanes_enable(struct kserdes_config *sc)
+{
+	switch (sc->phy_type) {
+	case KSERDES_PHY_SGMII:
+		return kserdes_sgmii_lanes_enable(sc);
+	case KSERDES_PHY_XGE:
+		return kserdes_xge_lanes_enable(sc);
+	case KSERDES_PHY_PCIE:
+		return kserdes_pcie_lanes_enable(sc);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int kserdes_init(struct phy *phy)
+{
+	struct kserdes_dev *sd = phy_get_drvdata(phy);
+	struct kserdes_config *sc = &sd->sc;
+	int ret;
+
+	switch (sc->phy_type) {
+	case KSERDES_PHY_SGMII:
+		ret = kserdes_sgmii_init(sc);
+		break;
+	case KSERDES_PHY_XGE:
+		ret = kserdes_xge_init(sc);
+		break;
+	case KSERDES_PHY_PCIE:
+		ret = kserdes_pcie_init(sc);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret < 0) {
+		dev_err(sd->dev, "serdes initialization failed %d\n", ret);
+		goto done;
+	}
+
+	ret = kserdes_lanes_enable(sc);
+	if (ret < 0) {
+		dev_err(sd->dev, "serdes lanes enable failed: %d\n", ret);
+		goto done;
+	}
+
+	dev_dbg(sd->dev, "serdes config done lanes(mask) 0x%x\n", ret);
+
+done:
+	return ret;
+}
+
+static int kserdes_of_parse_lane(struct device *dev,
+				 struct device_node *np,
+				 struct kserdes_config *sc)
+{
+	struct kserdes_lane_config *lc;
+	struct kserdes_equalizer *eq;
+	struct kserdes_tx_coeff *tc;
+	int lane_num, ret;
+
+	ret = of_property_read_u32(np, "reg", &lane_num);
+	if (ret) {
+		dev_err(dev, "Failed to parse reg\n");
+		return -EINVAL;
+	}
+
+	if (lane_num >= sc->lanes) {
+		dev_err(dev, "Invalid lane number %u\n", lane_num);
+		return -EINVAL;
+	}
+
+	lc = &sc->lane[lane_num];
+	lc->enable = true;
+	dev_dbg(dev, "lane %d enabled\n", lane_num);
+
+	if (of_property_read_u32(np, "control-rate", &lc->ctrl_rate)) {
+		dev_info(dev, "use default lane control-rate: %u\n",
+			 lc->ctrl_rate);
+	}
+	dev_dbg(dev, "lane control-rate: %d\n", lc->ctrl_rate);
+
+	if (of_find_property(np, "loopback", NULL))
+		lc->loopback = true;
+	else
+		lc->loopback = false;
+
+	dev_dbg(dev, "lane loopback: %d\n", lc->loopback);
+
+	eq = &lc->rx_start;
+	if (of_property_read_u32_array(np, "rx-start", &eq->att, 2)) {
+		dev_info(dev, "use default lane rx-start 0 0\n");
+		eq->att = 0;
+		eq->boost = 0;
+	}
+	dev_dbg(dev, "lane rx-start: %d %d\n", eq->att, eq->boost);
+
+	eq = &lc->rx_force;
+	if (of_property_read_u32_array(np, "rx-force", &eq->att, 2)) {
+		dev_info(dev, "use default lane rx-force 0 0\n");
+		eq->att = 0;
+		eq->boost = 0;
+	}
+	dev_dbg(dev, "lane rx-force: %d %d\n", eq->att, eq->boost);
+
+	tc = &lc->tx_coeff;
+	if (of_property_read_u32_array(np, "tx-coeff", &tc->c1, 5)) {
+		dev_info(dev, "use default tx-coeff 0\n");
+		tc->c1 = 0;
+	}
+	dev_dbg(dev, "tx-coeff: %d %d %d %d %d\n",
+		tc->c1, tc->c2, tc->cm, tc->att, tc->vreg);
+
+	return 0;
+}
+
+static void kserdes_set_sgmii_defaults(struct kserdes_config *sc)
+{
+	int i;
+
+	sc->link_rate		= KSERDES_LINK_RATE_1P25G;
+	sc->lanes		= 4;
+	sc->rx_force_enable	= false;
+
+	for (i = 0; i < sc->lanes; i++) {
+		memset(&sc->lane[i], 0, sizeof(sc->lane[i]));
+		sc->lane[i].ctrl_rate = KSERDES_QUARTER_RATE;
+	}
+}
+
+static void kserdes_set_xge_defaults(struct kserdes_config *sc)
+{
+	int i;
+
+	sc->link_rate		= KSERDES_LINK_RATE_10P3125G;
+	sc->lanes		= 2;
+	sc->rx_force_enable	= false;
+
+	for (i = 0; i < sc->lanes; i++) {
+		memset(&sc->lane[i], 0, sizeof(sc->lane[i]));
+		sc->lane[i].ctrl_rate = KSERDES_FULL_RATE;
+	}
+}
+
+static void kserdes_set_pcie_defaults(struct kserdes_config *sc)
+{
+	int i;
+
+	sc->link_rate		= KSERDES_LINK_RATE_5G;
+	sc->lanes		= 2;
+	sc->rx_force_enable	= false;
+
+	for (i = 0; i < sc->lanes; i++)
+		memset(&sc->lane[i], 0, sizeof(sc->lane[i]));
+}
+
+static void kserdes_set_defaults(struct kserdes_config *sc,
+				 enum KSERDES_PHY_TYPE phy_type)
+{
+	switch (phy_type) {
+	case KSERDES_PHY_SGMII:
+		kserdes_set_sgmii_defaults(sc);
+		break;
+	case KSERDES_PHY_XGE:
+		kserdes_set_xge_defaults(sc);
+		break;
+	case KSERDES_PHY_PCIE:
+		kserdes_set_pcie_defaults(sc);
+		break;
+	default:
+		break;
+	}
+}
+
+static int kserdes_of_parse(struct kserdes_dev *sd,
+			    struct device_node *np)
+{
+	struct kserdes_config *sc = &sd->sc;
+	struct device_node *lanes_np, *child;
+	struct device *dev = sd->dev;
+	struct resource res;
+	void __iomem *regs;
+	int ret;
+
+	ret = of_address_to_resource(np, SERDES_REG_INDEX, &res);
+	if (ret) {
+		dev_err(dev, "Can't xlate serdes reg addr of node(%s)\n",
+			np->name);
+		return ret;
+	}
+
+	regs = devm_ioremap_resource(dev, &res);
+	if (IS_ERR(regs)) {
+		dev_err(dev, "Failed to map serdes register base\n");
+		return PTR_ERR(regs);
+	}
+	sc->regs = regs;
+
+	if (of_device_is_compatible(np, "ti,keystone-serdes-gbe")) {
+		sc->phy_type = KSERDES_PHY_SGMII;
+	} else if (of_device_is_compatible(np, "ti,keystone-serdes-xgbe")) {
+		sc->phy_type = KSERDES_PHY_XGE;
+	} else if (of_device_is_compatible(np, "ti,keystone-serdes-pcie")) {
+		sc->phy_type = KSERDES_PHY_PCIE;
+	} else {
+		dev_err(dev, "unknown phy type\n");
+		return -EINVAL;
+	}
+
+	sc->dev = dev;
+
+	/* Set the defaults base on phy type */
+	kserdes_set_defaults(sc, sc->phy_type);
+
+	sc->peripheral_regmap =
+		syscon_regmap_lookup_by_phandle(np, "syscon-peripheral");
+	if (!sc->peripheral_regmap && IS_ERR(sc->peripheral_regmap)) {
+		dev_err(sc->dev,
+			"failed to get syscon-peripheral regmap\n");
+		return PTR_ERR(sc->peripheral_regmap);
+	}
+
+	sc->pcsr_regmap = syscon_regmap_lookup_by_phandle(np, "syscon-link");
+	if (!sc->pcsr_regmap && IS_ERR(sc->pcsr_regmap)) {
+		dev_err(sc->dev,
+			"failed to get syscon-link regmap\n");
+		return PTR_ERR(sc->pcsr_regmap);
+	}
+
+	if (of_property_read_u32(np, "link-rate-kbps", &sc->link_rate)) {
+		dev_info(dev, "use default link-rate-kbps: %u\n",
+			 sc->link_rate);
+	}
+
+	if (of_property_read_u32(np, "num-lanes", &sc->lanes))
+		dev_info(dev, "use default num-lanes %d\n", sc->lanes);
+
+	if (sc->lanes > KSERDES_MAX_LANES) {
+		sc->lanes = KSERDES_MAX_LANES;
+		dev_info(dev, "use max allowed lanes %d\n", sc->lanes);
+	}
+
+	if (of_property_read_bool(np, "rx-force-enable"))
+		sc->rx_force_enable = true;
+	else
+		sc->rx_force_enable = false;
+
+	lanes_np = of_get_child_by_name(np, "lanes");
+	if (lanes_np) {
+		for_each_available_child_of_node(lanes_np, child) {
+			ret = kserdes_of_parse_lane(dev, child, sc);
+			if (ret) {
+				of_node_put(child);
+				of_node_put(lanes_np);
+				return ret;
+			}
+			of_node_put(child);
+		}
+		of_node_put(lanes_np);
+	}
+
+	return 0;
+}
+
+static struct phy_ops kserdes_ops = {
+	.init		= kserdes_init,
+	.owner		= THIS_MODULE,
+};
+
+static int kserdes_probe(struct platform_device *pdev)
+{
+	struct phy_provider *phy_provider;
+	struct kserdes_dev *sd;
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	sd = devm_kzalloc(dev, sizeof(*sd), GFP_KERNEL);
+	if (!sd)
+		return -ENOMEM;
+
+	sd->dev = dev;
+
+	ret = kserdes_of_parse(sd, np);
+	if (ret)
+		return ret;
+
+	dev_set_drvdata(dev, sd);
+	sd->phy = devm_phy_create(dev, NULL, &kserdes_ops);
+	if (IS_ERR(sd->phy))
+		return PTR_ERR(sd->phy);
+
+	phy_set_drvdata(sd->phy, sd);
+	phy_provider = devm_of_phy_provider_register(sd->dev,
+						     of_phy_simple_xlate);
+
+	if (IS_ERR(phy_provider))
+		return PTR_ERR_OR_ZERO(phy_provider);
+
+	dev_vdbg(&pdev->dev, "probed");
+	return 0;
+}
+
+static const struct of_device_id kserdes_of_match[] = {
+	{ .compatible = "ti,keystone-serdes-gbe" },
+	{ .compatible = "ti,keystone-serdes-pcie" },
+	{ .compatible = "ti,keystone-serdes-xgbe" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, kserdes_of_match);
+
+static struct platform_driver kserdes_driver = {
+	.probe	= kserdes_probe,
+	.driver = {
+		.of_match_table	= kserdes_of_match,
+		.name  = "ti,keystone-serdes",
+	}
+};
+
+static int __init keystone_serdes_phy_init(void)
+{
+	return platform_driver_register(&kserdes_driver);
+}
+module_init(keystone_serdes_phy_init);
+
+static void __exit keystone_serdes_phy_exit(void)
+{
+	platform_driver_unregister(&kserdes_driver);
+}
+module_exit(keystone_serdes_phy_exit);
+
+MODULE_AUTHOR("WingMan Kwok <w-kwok2@ti.com>");
+MODULE_DESCRIPTION("TI Keystone SerDes driver");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 14:25   ` WingMan Kwok
  0 siblings, 0 replies; 63+ messages in thread
From: WingMan Kwok @ 2015-10-15 14:25 UTC (permalink / raw
  To: linux-arm-kernel

On TI's Keystone platforms, several peripherals such as the
gbe ethernet switch, 10gbe ethernet switch and PCIe controller
require the use of a SerDes for converting SoC parallel data into
serialized data that can be output over a high-speed electrical
interface, and also converting high-speed serial input data
into parallel data that can be processed by the SoC.  The
SerDeses used by those peripherals, though they may be different,
are largely similar in functionality and setup.

This patch provides a SerDes phy driver implementation that can be
used by the above mentioned peripheral drivers to configure their
respective SerDeses.

v1:
	- see cover letter for review comments addressed.

Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
---
 Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
 drivers/phy/Kconfig                              |    8 +
 drivers/phy/Makefile                             |    1 +
 drivers/phy/phy-keystone-serdes.c                | 2373 ++++++++++++++++++++++
 4 files changed, 2660 insertions(+)
 create mode 100644 drivers/phy/phy-keystone-serdes.c

diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt
index 9cf9446..4dca271 100644
--- a/Documentation/devicetree/bindings/phy/ti-phy.txt
+++ b/Documentation/devicetree/bindings/phy/ti-phy.txt
@@ -115,4 +115,282 @@ sata_phy: phy at 4A096000 {
 	clock-names = "sysclk", "refclk";
 	syscon-pllreset = <&scm_conf 0x3fc>;
 	#phy-cells = <0>;
+
+TI Keystone SerDes PHY
+======================
+
+Required properties:
+ - compatible: should be one of
+	* "ti,keystone-serdes-gbe"
+	* "ti,keystone-serdes-xgbe"
+	* "ti,keystone-serdes-pcie"
+ - reg:
+	* base address and length of the SerDes register set
+ - reg-names:
+	* "serdes"
+		- name of the reg SerDes register set
+ - #phy-cells:
+	* From the generic phy bindings, must be 0;
+ - num-lanes:
+	* Number of lanes in SerDes.
+
+Optional properties:
+ - syscon-peripheral:
+	* Handle to the subsystem register region of the peripheral
+	  inside which the SerDes exists.
+ - syscon-link:
+	* Handle to the Link register region of the peripheral inside
+	  which the SerDes exists.  Example: it is the PCSR register
+	  region in the case of 10gbe.
+ - rx-force-enable:
+	* Include this property if receiver attenuation and boost are
+	  to be configured with specific values defined in rx-force.
+ - link-rate-kbps:
+	* SerDes link rate to be configured, in kbps.
+
+
+For gbe and 10gbe SerDes, it is optional to represent each lane as
+a sub-node, which can be enabled or disabled individually using
+the "status" property.
+
+Required properties (lane sub-node):
+ - reg:
+	* lane number
+
+Optional properties (lane sub-node):
+ - control-rate:
+	* Lane control rate
+		0: full rate
+		1: half rate
+		2: quarter rate
+ - rx-start:
+	* Initial lane rx equalizer attenuation and boost configurations.
+	* Must be array of 2 integers.
+ - rx-force:
+	* Forced lane rx equalizer attenuation and boost configurations.
+	* Must be array of 2 integers.
+ - tx-coeff:
+	* Lane c1, c2, cm, attenuation and regulator output voltage
+	  configurations.
+	* Must be array of 5 integers.
+ - loopback:
+	* Include this property to enable loopback at the SerDes
+	  lane level.
+
+Example for Keystone K2E GBE:
+-----------------------------
+
+gbe_serdes0: gbe_serdes at 232a000 {
+	#phy-cells		= <0>;
+	compatible		= "ti,keystone-serdes-gbe";
+	reg			= <0x0232a000 0x2000>;
+	reg-names		= "serdes";
+	link-rate-kbps		= <1250000>;
+	num-lanes		= <4>;
+	lanes {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		lane at 0 {
+			/*loopback;*/
+			reg		= <0>;
+			control-rate	= <2>; /* quart */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <0 0 0 12 4>;
+			       /* c1 c2 cm att vreg */
+		};
+		lane at 1 {
+			/*loopback;*/
+			reg		= <1>;
+			control-rate	= <2>; /* quart */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <0 0 0 12 4>;
+			       /* c1 c2 cm att vreg */
+		};
+	};
+};
+
+gbe_serdes1: gbe_serdes at 2324000 {
+	#phy-cells		= <0>;
+	compatible		= "ti,keystone-serdes-gbe";
+	reg			= <0x02324000 0x2000>;
+	reg-names		= "serdes";
+	link-rate-kbps		= <1250000>;
+	num-lanes		= <4>;
+	lanes {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		lane at 0 {
+			/*loopback;*/
+			reg		= <0>;
+			control-rate	= <2>; /* quart */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <0 0 0 12 4>;
+			       /* c1 c2 cm att vreg */
+		};
+		lane at 1 {
+			/*loopback;*/
+			reg		= <1>;
+			control-rate	= <2>; /* quart */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <0 0 0 12 4>;
+			       /* c1 c2 cm att vreg */
+		};
+	};
+};
+
+netcp: netcp at 24000000 {
+	...
+
+	netcp-devices {
+		...
+
+		gbe at 200000 { /* ETHSS */
+			...
+			serdeses {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				serdes at 0 {
+					reg = <0>;
+					phys = <&gbe_serdes0>;
+					status = "ok";
+				};
+				serdes at 1 {
+					reg = <1>;
+					phys = <&gbe_serdes1>;
+					status = "ok";
+				};
+
+			...
+			};
+
+		...
+		};
+
+	...
+	};
+};
+
+Example for Keystone PCIE:
+--------------------------
+
+	pcie0_phy: serdes_phy at 2320000 {
+		#phy-cells = <0>;
+		compatible = "ti,keystone-serdes-pcie";
+		reg = <0x02320000 0x4000>;
+		reg-names = "serdes";
+		num-lanes = <2>;
+	};
+
+
+Then the PHY can be used in PCIe controller node as
+
+	pcie0: pcie at 21800000 {
+		...
+
+		serdeses {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			serdes at 0 {
+				reg = <0>;
+				phys = <&pcie0_phy>;
+				status = "disabled";
+			};
+		};
+	}
+
+Example for K2E 10GBE:
+----------------------
+
+Define the syscon regmaps for 10gbe subsystem:
+
+xgbe_subsys: xgbe_subsys at 2f00000 {
+	status		= "ok";
+	compatible	= "syscon";
+	reg		= <0x02f00000 0x100>;
+};
+
+Define the syscon regmaps for 10gbe pcsr:
+
+xgbe_pcsr: xgbe_pcsr at 2f00000 {
+	status		= "ok";
+	compatible	= "syscon";
+	reg		= <0x02f00600 0x100>;
+};
+
+Define the 10gbe SerDes node:
+
+xgbe_serdes: xgbe_serdes at 231e000 {
+	status			= "ok";
+	#phy-cells		= <0>;
+	compatible		= "ti,keystone-serdes-xgbe";
+	reg			= <0x0231e000 0x2000>;
+	reg-names		= "serdes";
+	link-rate-kbps		= <10312500>;
+	num-lanes		= <2>;
+	syscon-peripheral	= <&xgbe_subsys>;
+	syscon-link		= <&xgbe_pcsr>;
+	lanes {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		lane at 0 {
+			/*loopback;*/
+			reg		= <0>;
+			control-rate	= <0>; /* full */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <2 0 0 12 4>;
+				/* c1 c2 cm att vreg */
+		};
+		lane at 1 {
+			/*loopback;*/
+			reg		= <1>;
+			control-rate	= <0>; /* full */
+			rx-start	= <7 5>;
+			rx-force	= <1 1>;
+			tx-coeff	= <2 0 0 12 4>;
+				/* c1 c2 cm att vreg */
+		};
+	};
+};
+
+Then the 10gbe SerDes PHY can be used in the 10gbe switch node:
+
+netcpx: netcpx at 2f00000 {
+
+	...
+
+	netcp-devices {
+
+		...
+
+		xgbe at 2f00000 {
+
+			...
+
+			syscon-subsys = <&xgbe_subsys>;
+			syscon-link = <&xgbe_pcsr>;
+
+			...
+
+			serdeses {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				serdes at 0 {
+					reg = <0>;
+					phys = <&xgbe_serdes>;
+				};
+			};
+
+
+			...
+
+		};
+	};
+
+	...
+
 };
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 47da573..8fc21a4 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -118,6 +118,14 @@ config PHY_RCAR_GEN2
 	help
 	  Support for USB PHY found on Renesas R-Car generation 2 SoCs.
 
+config PHY_TI_KEYSTONE_SERDES
+	tristate "TI Keystone SerDes PHY support"
+	depends on OF && ARCH_KEYSTONE
+	select GENERIC_PHY
+	help
+	  This option enables support for TI Keystone SerDes PHY found
+	  in peripherals GBE, 10GBE and PCIe.
+
 config OMAP_CONTROL_PHY
 	tristate "OMAP CONTROL PHY Driver"
 	depends on ARCH_OMAP2PLUS || COMPILE_TEST
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index a5b18c1..8cb365b 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -46,3 +46,4 @@ obj-$(CONFIG_PHY_QCOM_UFS) 	+= phy-qcom-ufs-qmp-14nm.o
 obj-$(CONFIG_PHY_TUSB1210)		+= phy-tusb1210.o
 obj-$(CONFIG_PHY_BRCMSTB_SATA)		+= phy-brcmstb-sata.o
 obj-$(CONFIG_PHY_PISTACHIO_USB)		+= phy-pistachio-usb.o
+obj-$(CONFIG_PHY_TI_KEYSTONE_SERDES)	+= phy-keystone-serdes.o
diff --git a/drivers/phy/phy-keystone-serdes.c b/drivers/phy/phy-keystone-serdes.c
new file mode 100644
index 0000000..f213006
--- /dev/null
+++ b/drivers/phy/phy-keystone-serdes.c
@@ -0,0 +1,2373 @@
+/*
+ * Texas Instruments Keystone SerDes driver
+ * Authors: WingMan Kwok <w-kwok2@ti.com>
+ *
+ * This is the SerDes Phy driver for Keystone devices. This is
+ * required to support PCIe RC functionality based on designware
+ * PCIe hardware, gbe and 10gbe found on these devices.
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The contents of the array k2_100mhz_pcie_5gbps_serdes is covered by BSD
+ * license.
+ */
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/firmware.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+/*
+ * Keystone2 SERDES registers
+ */
+/* 0x1fc0 - 0x1fff */
+#define KSERDES_SS_OFFSET	0x1fc0
+/* 0x1fc0 */
+#define MOD_VER_REG		(KSERDES_SS_OFFSET + 0x00)
+/* 0x1fc4 */
+#define MEM_ADR_REG		(KSERDES_SS_OFFSET + 0x04)
+/* 0x1fc8 */
+#define MEM_DAT_REG		(KSERDES_SS_OFFSET + 0x08)
+/* 0x1fcc */
+#define MEM_DATINC_REG		(KSERDES_SS_OFFSET + 0x0c)
+/* 0x1fd0 */
+#define CPU_CTRL_REG		(KSERDES_SS_OFFSET + 0x10)
+/* 0x1fe0, 0x1fe4 */
+#define LANE_CTRL_STS_REG(x)	(KSERDES_SS_OFFSET + 0x20 + (x * 0x04))
+/* 0x1ff0 */
+#define LINK_LOSS_WAIT_REG	(KSERDES_SS_OFFSET + 0x30)
+/* 0x1ff4 */
+#define PLL_CTRL_REG		(KSERDES_SS_OFFSET + 0x34)
+
+/* CMU0 SS 0x0000 - 0x01ff */
+#define CMU0_SS_OFFSET		0x0000
+#define CMU0_REG(x)		(CMU0_SS_OFFSET + x)
+
+/* LANE SS 0x0200 - 0x03ff, 0x0400 - 0x05ff, ... */
+#define LANE0_SS_OFFSET		0x0200
+#define LANEX_SS_OFFSET(x)	(LANE0_SS_OFFSET * (x + 1))
+#define LANEX_REG(x, y)		(LANEX_SS_OFFSET(x) + y)
+
+/* CML SS 0x0a00 - 0x0bff */
+#define CML_SS_OFFSET		0x0a00
+#define CML_REG(x)		(CML_SS_OFFSET + x)
+
+/* CMU1 SS 0x0c00 - 0x0dff */
+#define CMU1_SS_OFFSET		0x0c00
+#define CMU1_REG(x)		(CMU1_SS_OFFSET + x)
+
+/*
+ * XGE PCS-R registers
+ */
+#define PCSR_OFFSET(x)		(x * 0x80)
+
+#define PCSR_TX_CTL(x)		(PCSR_OFFSET(x) + 0x00)
+#define PCSR_TX_STATUS(x)	(PCSR_OFFSET(x) + 0x04)
+#define PCSR_RX_CTL(x)		(PCSR_OFFSET(x) + 0x08)
+#define PCSR_RX_STATUS(x)	(PCSR_OFFSET(x) + 0x0C)
+
+#define XGE_CTRL_OFFSET		0x0c
+#define PCIE_PL_GEN2_OFFSET	0x180c
+
+#define reg_rmw(addr, value, mask) \
+	__raw_writel(((__raw_readl(addr) & (~(mask))) | \
+			(value & (mask))), (addr))
+
+/* Replaces bit field [msb:lsb] in register located
+ * at (base + offset) by val
+ */
+#define FINSR(base, offset, msb, lsb, val) \
+	reg_rmw((base) + (offset), ((val) << (lsb)), GENMASK((msb), (lsb)))
+
+/* This version of FEXTR is NOT safe for msb = 31, lsb = 0
+ * but then why would we need FEXTR for that case.
+ */
+#define FEXTR(val, msb, lsb) \
+	(((val) >> (lsb)) & ((1 << ((msb) - (lsb) + 1)) - 1))
+
+#define MOD_VER(serdes) \
+	((kserdes_readl(serdes, MOD_VER_REG) >> 16) & 0xffff)
+
+#define PHY_A(serdes) (MOD_VER(serdes) != 0x4eba)
+
+#define FOUR_LANE(serdes) \
+	((MOD_VER(serdes) == 0x4eb9) || (MOD_VER(serdes) == 0x4ebd))
+
+#define LANE_ENABLE(sc, n) ((sc)->lane[n].enable)
+
+#define for_each_enable_lane(func, sc)			\
+	do {						\
+		int i;					\
+		for (i = 0; i < (sc)->lanes; i++) {	\
+			if (!LANE_ENABLE((sc), i))	\
+				continue;		\
+							\
+			(func)((sc), i);		\
+		}					\
+	} while (0)
+
+#define for_each_lane(func, sc)				\
+	do {						\
+		int i;					\
+		for (i = 0; i < (sc)->lanes; i++) {	\
+			(func)((sc), i);		\
+		}					\
+	} while (0)
+
+#define for_each_enable_lane_return(func, sc, r)	\
+	do {						\
+		int i;					\
+		(r) = 0;				\
+		for (i = 0; i < (sc)->lanes; i++) {	\
+			if (!LANE_ENABLE((sc), i))	\
+				continue;		\
+							\
+			(r) = (func)((sc), i);		\
+			if ((r))			\
+				break;			\
+		}					\
+	} while (0)
+
+#define MAX_COMPARATORS			5
+#define DFE_OFFSET_SAMPLES		100
+
+/* CPU CTRL bits */
+#define CPU_EN			BIT(31)
+#define CPU_GO			BIT(30)
+#define POR_EN			BIT(29)
+#define CPUREG_EN		BIT(28)
+#define AUTONEG_CTL		BIT(27)
+#define DATASPLIT		BIT(26)
+#define LNKTRN_SIG_DET		BIT(8)
+
+#define ANEG_LINK_CTL_10GKR_MASK	GENMASK(21, 20)
+#define ANEG_LINK_CTL_1GKX_MASK		GENMASK(17, 16)
+#define ANEG_LINK_CTL_1G10G_MASK \
+	(ANEG_LINK_CTL_10GKR_MASK | ANEG_LINK_CTL_1GKX_MASK)
+
+#define ANEG_1G_10G_OPT_MASK		GENMASK(7, 5)
+
+#define SERDES_REG_INDEX		0
+
+/* SERDES internal memory */
+#define KSERDES_XFW_MEM_SIZE		SZ_64K
+#define KSERDES_XFW_CONFIG_MEM_SIZE	SZ_64
+#define KSERDES_XFW_NUM_PARAMS		5
+
+/* Last 64B of the 64KB internal mem is for parameters */
+#define KSERDES_XFW_CONFIG_START_ADDR \
+	(KSERDES_XFW_MEM_SIZE - KSERDES_XFW_CONFIG_MEM_SIZE)
+
+#define KSERDES_XFW_PARAM_START_ADDR \
+	(KSERDES_XFW_MEM_SIZE - (KSERDES_XFW_NUM_PARAMS * 4))
+
+/* All firmware file names end up here. List the firmware file names below.
+ * Newest first. Search starts from the 0-th array entry until a firmware
+ * file is found.
+ */
+const char *ks2_gbe_serdes_firmwares[] = {"ks2_gbe_serdes.bin"};
+const char *ks2_xgbe_serdes_firmwares[] = {"ks2_xgbe_serdes.bin"};
+const char *ks2_pcie_serdes_firmwares[] = {"ks2_pcie_serdes.bin"};
+
+/* SERDES Link Rate Kbps */
+enum KSERDES_LINK_RATE {
+	KSERDES_LINK_RATE_1P25G		=  1250000,
+	KSERDES_LINK_RATE_3P125G	=  3125000,
+	KSERDES_LINK_RATE_4P9152G	=  4915200,
+	KSERDES_LINK_RATE_5G		=  5000000,
+	KSERDES_LINK_RATE_6P144G	=  6144000,
+	KSERDES_LINK_RATE_6P25G		=  6250000,
+	KSERDES_LINK_RATE_7P3728G	=  7372800,
+	KSERDES_LINK_RATE_9P8304G	=  9830400,
+	KSERDES_LINK_RATE_10G		= 10000000,
+	KSERDES_LINK_RATE_10P3125G	= 10312500,
+	KSERDES_LINK_RATE_12P5G		= 12500000,
+};
+
+/* SERDES Lane Control Rate */
+enum KSERDES_LANE_CTRL_RATE {
+	KSERDES_FULL_RATE,
+	KSERDES_HALF_RATE,
+	KSERDES_QUARTER_RATE,
+};
+
+enum KSERDES_PHY_TYPE {
+	KSERDES_PHY_SGMII,
+	KSERDES_PHY_XGE,
+	KSERDES_PHY_PCIE,
+	KSERDES_PHY_HYPERLINK,
+};
+
+struct kserdes_tx_coeff {
+	u32	c1;
+	u32	c2;
+	u32	cm;
+	u32	att;
+	u32	vreg;
+};
+
+struct kserdes_equalizer {
+	u32	att;
+	u32	boost;
+};
+
+struct kserdes_lane_config {
+	bool				enable;
+	u32				ctrl_rate;
+	struct kserdes_tx_coeff		tx_coeff;
+	struct kserdes_equalizer	rx_start;
+	struct kserdes_equalizer	rx_force;
+	bool				loopback;
+};
+
+#define KSERDES_MAX_LANES		4
+
+struct kserdes_fw_config {
+	bool				on;
+	u32				rate;
+	u32				link_loss_wait;
+	u32				lane_seeds;
+	u32				fast_train;
+	u32				active_lane;
+	u32				c1, c2, cm, attn, boost, dlpf, cdrcal;
+	u32				lane_config[KSERDES_MAX_LANES];
+};
+
+struct kserdes_config {
+	struct device			*dev;
+	enum KSERDES_PHY_TYPE		phy_type;
+	u32				lanes;
+	void __iomem			*regs;
+	struct regmap			*peripheral_regmap;
+	struct regmap			*pcsr_regmap;
+	/* non-fw specific */
+	const char			*init_fw;
+	struct serdes_cfg		*init_cfg;
+	int				init_cfg_len;
+	enum KSERDES_LINK_RATE		link_rate;
+	bool				rx_force_enable;
+	struct kserdes_lane_config	lane[KSERDES_MAX_LANES];
+	/* fw specific */
+	bool				firmware;
+	struct kserdes_fw_config	fw;
+};
+
+struct kserdes_dev {
+	struct device *dev;
+	struct phy *phy;
+	struct kserdes_config sc;
+};
+
+struct kserdes_comparator_tap_offsets {
+	u32 cmp;
+	u32 tap1;
+	u32 tap2;
+	u32 tap3;
+	u32 tap4;
+	u32 tap5;
+};
+
+struct kserdes_lane_offsets {
+	struct kserdes_comparator_tap_offsets ct_ofs[MAX_COMPARATORS];
+};
+
+struct kserdes_offsets {
+	struct kserdes_lane_offsets lane_ofs[KSERDES_MAX_LANES];
+};
+
+struct serdes_cfg {
+	u32 ofs;
+	u32 msb;
+	u32 lsb;
+	u32 val;
+};
+
+static inline u32 kserdes_readl(void __iomem *base, u32 offset)
+{
+	return readl(base + offset);
+}
+
+static inline void kserdes_writel(void __iomem *base, u32 offset, u32 value)
+{
+	writel(value, base + offset);
+}
+
+static void kserdes_do_config(void __iomem *base,
+			      struct serdes_cfg *cfg, u32 size)
+{
+	u32 i;
+
+	for (i = 0; i < size; i++)
+		FINSR(base, cfg[i].ofs, cfg[i].msb, cfg[i].lsb, cfg[i].val);
+}
+
+static int kserdes_load_init_fw(struct kserdes_config *sc,
+				const char **a_firmwares,
+				int n_firmwares)
+{
+	const struct firmware *fw;
+	bool found = false;
+	int ret, i;
+
+	for (i = 0; i < n_firmwares; i++) {
+		if (a_firmwares[i]) {
+			ret = request_firmware(&fw, a_firmwares[i], sc->dev);
+			if (!ret) {
+				found = true;
+				break;
+			}
+		}
+	}
+
+	if (!found) {
+		dev_err(sc->dev, "can't get any serdes init fw");
+		return -ENODEV;
+	}
+
+	sc->init_fw = a_firmwares[i];
+	sc->init_cfg = devm_kzalloc(sc->dev, fw->size, GFP_KERNEL);
+	memcpy((void *)sc->init_cfg, fw->data,  fw->size);
+	sc->init_cfg_len = fw->size;
+	release_firmware(fw);
+
+	kserdes_do_config(sc->regs, sc->init_cfg,
+			  sc->init_cfg_len / sizeof(struct serdes_cfg));
+
+	return 0;
+}
+
+static inline u32 _kserdes_read_tbus_val(void __iomem *sregs)
+{
+	u32 tmp;
+
+	if (PHY_A(sregs)) {
+		tmp  = ((kserdes_readl(sregs, CMU0_REG(0xec))) >> 24) & 0x0ff;
+		tmp |= ((kserdes_readl(sregs, CMU0_REG(0xfc))) >> 16) & 0xf00;
+	} else {
+		tmp  = ((kserdes_readl(sregs, CMU0_REG(0xf8))) >> 16) & 0xfff;
+	}
+
+	return tmp;
+}
+
+static void _kserdes_write_tbus_addr(void __iomem *sregs, int select, int ofs)
+{
+	if (select && !FOUR_LANE(sregs))
+		++select;
+
+	if (PHY_A(sregs))
+		FINSR(sregs, CMU0_REG(0x8), 31, 24, ((select << 5) + ofs));
+	else
+		FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((select << 8) + ofs));
+}
+
+static u32 _kserdes_read_select_tbus(void __iomem *sregs, int select, int ofs)
+{
+	/* set tbus address */
+	_kserdes_write_tbus_addr(sregs, select, ofs);
+	/* get tbus value */
+	return _kserdes_read_tbus_val(sregs);
+}
+
+static inline void kserdes_tap1_patch(struct kserdes_config *sc)
+{
+	FINSR(sc->regs, CML_REG(0xbc), 28, 24, 0x1e);
+}
+
+static inline void kserdes_set_tx_idle(struct kserdes_config *sc, u32 lane)
+{
+	if (sc->phy_type != KSERDES_PHY_XGE)
+		FINSR(sc->regs, LANEX_REG(lane, 0xb8), 17, 16, 3);
+
+	FINSR(sc->regs, LANE_CTRL_STS_REG(lane), 25, 24, 3);
+	FINSR(sc->regs, LANEX_REG(lane, 0x28), 21, 20, 0);
+}
+
+static inline void kserdes_clr_tx_idle(struct kserdes_config *sc, u32 lane)
+{
+	if (sc->phy_type != KSERDES_PHY_XGE)
+		FINSR(sc->regs, LANEX_REG(lane, 0xb8), 17, 16, 0);
+
+	FINSR(sc->regs, LANE_CTRL_STS_REG(lane), 25, 24, 0);
+	FINSR(sc->regs, LANEX_REG(lane, 0x28), 21, 20, 0);
+}
+
+static inline void kserdes_cdfe_enable(struct kserdes_config *sc, u32 lane)
+{
+	FINSR(sc->regs, LANEX_REG(lane, 0x94), 24, 24, 0x1);
+}
+
+static inline void kserdes_cdfe_force_calibration_enable(
+			struct kserdes_config *sc, u32 lane)
+{
+	FINSR(sc->regs, LANEX_REG(lane, 0x98), 0, 0, 0x1);
+}
+
+static void kserdes_phya_lane_patch(struct kserdes_config *sc, u32 lane)
+{
+	/* pma_ln_vreg */
+	FINSR(sc->regs, LANEX_REG(lane, 0x18), 25, 24, 0x2);
+	/* pma_ln_vregh */
+	FINSR(sc->regs, LANEX_REG(lane, 0x18), 27, 26, 0x2);
+	/* pma_int_step */
+	FINSR(sc->regs, LANEX_REG(lane, 0x14), 15, 13, 0x1);
+	/* turn off att_boost */
+	FINSR(sc->regs, LANEX_REG(lane, 0x4c), 19, 16, 0xf);
+	/* set dfe_bias to 10 */
+	FINSR(sc->regs, LANEX_REG(lane, 0x4c), 23, 20, 0xa);
+	/* Set offset average num of samples to max value */
+	FINSR(sc->regs, LANEX_REG(lane, 0x78), 30, 24, 0x7f);
+}
+
+static void kserdes_phyb_patch(struct kserdes_config *sc)
+{
+	/* Enables the Center DFE */
+	for_each_enable_lane(kserdes_cdfe_enable, sc);
+
+	/* setting initial cdfe */
+	FINSR(sc->regs, CML_REG(0x108), 23, 16, 0x04);
+
+	/* setting rx tap */
+	FINSR(sc->regs, CML_REG(0xbc), 28, 24, 0x0);
+
+	/* enable cdfe_ln_force_cal for cdfe */
+	for_each_lane(kserdes_cdfe_force_calibration_enable, sc);
+}
+
+static inline void kserdes_set_lane_starts(struct kserdes_config *sc, u32 lane)
+{
+	/* att start -1 for short channel */
+	FINSR(sc->regs, LANEX_REG(lane, 0x8c), 11, 8,
+	      sc->lane[lane].rx_start.att);
+	/* boost start -3 for short channel */
+	FINSR(sc->regs, LANEX_REG(lane, 0x8c), 15, 12,
+	      sc->lane[lane].rx_start.boost);
+}
+
+static void kserdes_phy_patch(struct kserdes_config *sc)
+{
+	if (sc->phy_type == KSERDES_PHY_XGE)
+		kserdes_phyb_patch(sc);
+	else if (sc->link_rate >= KSERDES_LINK_RATE_9P8304G)
+		for_each_enable_lane(kserdes_phya_lane_patch, sc);
+
+	/* Set ATT and BOOST start values for each lane */
+	for_each_enable_lane(kserdes_set_lane_starts, sc);
+}
+
+static inline void _kserdes_set_training_pattern(void __iomem *sregs)
+{
+	FINSR(sregs, CML_REG(0xc8), 5, 0, 0x0f);
+}
+
+static void kserdes_set_lane_overrides(struct kserdes_config *sc, u32 lane)
+{
+	u32 val_0, val_1, val;
+
+	/* read laneX_ctrl_i/laneX_pd_i */
+	val_0 = _kserdes_read_select_tbus(sc->regs, lane + 1, 0);
+
+	/* read laneX_rate_i */
+	val_1 = _kserdes_read_select_tbus(sc->regs, lane + 1, 1);
+
+	/* set RESET state */
+	val = 0;
+	/* user rate */
+	val |= ((val_1 >> 9) & 0x3) << 1;
+	/* user PD */
+	val |= (val_0 & 0x3) << 3;
+	/* user ctrl_i */
+	val |= ((val_0 >> 2) & 0x1ff) << 5;
+	/* set override */
+	val |= (1 << 14);
+	/* try claer TX Valid bits */
+	val &= ~0x60;
+
+	/* Only modify the reset bit and the overlay bit */
+	FINSR(sc->regs, LANEX_REG(lane, 0x028), 29, 15, val);
+}
+
+static inline void kserdes_assert_reset(struct kserdes_config *sc)
+{
+	for_each_enable_lane(kserdes_set_lane_overrides, sc);
+}
+
+static inline void kserdes_config_c1_c2_cm(struct kserdes_config *sc, u32 lane)
+{
+	u32 c1, c2, cm;
+
+	c1 = sc->lane[lane].tx_coeff.c1;
+	c2 = sc->lane[lane].tx_coeff.c2;
+	cm = sc->lane[lane].tx_coeff.cm;
+
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		/* TX Control override enable */
+		FINSR(sc->regs, LANEX_REG(lane, 0x8), 11,  8, (cm & 0xf));
+		FINSR(sc->regs, LANEX_REG(lane, 0x8),  4,  0, (c1 & 0x1f));
+		FINSR(sc->regs, LANEX_REG(lane, 0x8),  7,  5, (c2 & 0x7));
+		FINSR(sc->regs, LANEX_REG(lane, 0x4),
+		      18, 18, ((c2 >> 3) & 0x1));
+	} else {
+		FINSR(sc->regs, LANEX_REG(lane, 0x8), 15, 12, (cm & 0xf));
+		FINSR(sc->regs, LANEX_REG(lane, 0x8),  4,  0, (c1 & 0x1f));
+		FINSR(sc->regs, LANEX_REG(lane, 0x8), 11,  8, (c2 & 0xf));
+	}
+}
+
+static inline void kserdes_config_att_boost(struct kserdes_config *sc, u32 lane)
+{
+	u32 att, boost;
+
+	att = sc->lane[lane].rx_force.att;
+	boost = sc->lane[lane].rx_force.boost;
+
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		FINSR(sc->regs, LANEX_REG(lane, 0x98), 13, 13, 0);
+		FINSR(sc->regs, LANEX_REG(lane, 0x8c), 15, 12, boost);
+		FINSR(sc->regs, LANEX_REG(lane, 0x8c), 11, 8, att);
+	} else {
+		if (att != 1) {
+			FINSR(sc->regs, CML_REG(0x84), 0, 0, 0);
+			FINSR(sc->regs, CML_REG(0x8c), 24, 24, 0);
+			FINSR(sc->regs, LANEX_REG(lane, 0x8c), 11, 8, att);
+		}
+		if (boost != 1) {
+			FINSR(sc->regs, CML_REG(0x84), 1, 1, 0);
+			FINSR(sc->regs, CML_REG(0x8c), 25, 25, 0);
+			FINSR(sc->regs, LANEX_REG(lane, 0x8c), 15, 12, boost);
+		}
+	}
+}
+
+static void kserdes_set_tx_rx_fir_coeff(struct kserdes_config *sc, u32 lane)
+{
+	struct kserdes_tx_coeff *tc = &sc->lane[lane].tx_coeff;
+
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		/* Tx Swing */
+		FINSR(sc->regs, LANEX_REG(lane, 0x004), 29, 26, tc->att);
+		/* Regulator voltage */
+		FINSR(sc->regs, LANEX_REG(lane, 0x0a4), 2, 0, tc->vreg);
+	} else {
+		/* Tx Swing */
+		FINSR(sc->regs, LANEX_REG(lane, 0x004), 28, 25, tc->att);
+		/* Regulator voltage */
+		FINSR(sc->regs, LANEX_REG(lane, 0x084), 7, 5, tc->vreg);
+	}
+
+	kserdes_config_c1_c2_cm(sc, lane);
+
+	if (sc->rx_force_enable)
+		kserdes_config_att_boost(sc, lane);
+}
+
+static inline void _kserdes_force_signal_detect_low(
+				void __iomem *sregs, u32 lane)
+{
+	FINSR(sregs, LANEX_REG(lane, 0x004), 2, 1, 0x2);
+}
+
+static inline void kserdes_force_signal_detect_low(
+			struct kserdes_config *sc, u32 lane)
+{
+	_kserdes_force_signal_detect_low(sc->regs, lane);
+}
+
+static inline void _kserdes_force_signal_detect_high(
+				void __iomem *sregs, u32 lane)
+{
+	FINSR(sregs, LANEX_REG(lane, 0x004), 2, 1, 0x0);
+}
+
+static inline void kserdes_force_signal_detect_high(
+			struct kserdes_config *sc, u32 lane)
+{
+	_kserdes_force_signal_detect_high(sc->regs, lane);
+}
+
+static int kserdes_deassert_reset_poll_others(struct kserdes_config *sc)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(500);
+	u32 lanes_not_ok = 0;
+	u32 ofs = 28;
+	u32 ret, i;
+
+	/* assume all enable lanes not-ok (1) and all others
+	 * ok (0) to start
+	 */
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		lanes_not_ok |= (1 << i);
+	}
+
+	/* This is not a mistake.  For 2-laner, we
+	 * check bit 29 and 30,  NOT 28 and 29.
+	 */
+	if (!FOUR_LANE(sc->regs))
+		ofs = 29;
+
+	do {
+		for (i = 0; i < sc->lanes; i++) {
+			if (!LANE_ENABLE(sc, i))
+				continue;
+
+			/* no need to check again if this lane's status
+			 * is already good
+			 */
+			if (!(lanes_not_ok & (1 << i)))
+				continue;
+
+			ret = kserdes_readl(sc->regs, CML_REG(0x1f8));
+
+			/* clear corresponding lane_not_ok bit if
+			 * status is good (1)
+			 */
+			if (ret & BIT(ofs + i))
+				lanes_not_ok &= ~(1 << i);
+		}
+
+		/* get out if all lanes are good to go */
+		if (!lanes_not_ok)
+			return 0;
+
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+
+		cpu_relax();
+	} while (true);
+}
+
+static int kserdes_deassert_reset_poll_pcie(struct kserdes_config *sc)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(500);
+	u32 lanes_not_ok = 0;
+	u32 ret, i;
+
+	/* assume all enable lanes not-ok (1) and all others
+	 * ok (0) to start
+	 */
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		lanes_not_ok |= (1 << i);
+	}
+
+	do {
+		for (i = 0; i < sc->lanes; i++) {
+			if (!LANE_ENABLE(sc, i))
+				continue;
+
+			/* no need to check again if this lane's status
+			 * is already good
+			 */
+			if (!(lanes_not_ok & (1 << i)))
+				continue;
+
+			ret = _kserdes_read_select_tbus(sc->regs, i + 1, 0x02);
+
+			/* clear corresponding lane_not_ok bit if
+			 * status is good (0)
+			 */
+			if (!(ret & BIT(4)))
+				lanes_not_ok &= ~(1 << i);
+		}
+
+		/* get out if all lanes are good to go */
+		if (!lanes_not_ok)
+			return 0;
+
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+
+		cpu_relax();
+	} while (true);
+}
+
+static inline void _kserdes_lane_reset(void __iomem *serdes,
+				       u32 lane, u32 reset)
+{
+	if (reset)
+		FINSR(serdes, LANEX_REG(lane, 0x28), 29, 29, 0x1);
+	else
+		FINSR(serdes, LANEX_REG(lane, 0x28), 29, 29, 0x0);
+}
+
+static inline void kserdes_release_reset(struct kserdes_config *sc, u32 lane)
+{
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		/* set pma_cmu_sel to 1 */
+		FINSR(sc->regs, LANEX_REG(lane, 0x60), 0, 0, 0x1);
+	}
+	/* release reset */
+	_kserdes_lane_reset(sc->regs, lane, 0);
+}
+
+static int kserdes_deassert_reset(struct kserdes_config *sc, u32 poll)
+{
+	int ret = 0;
+
+	for_each_enable_lane(kserdes_release_reset, sc);
+
+	if (!poll)
+		goto done;
+
+	/* Check Lane OK */
+	if (sc->phy_type == KSERDES_PHY_PCIE)
+		ret = kserdes_deassert_reset_poll_pcie(sc);
+	else
+		ret = kserdes_deassert_reset_poll_others(sc);
+
+done:
+	return ret;
+}
+
+static inline void kserdes_lane_disable(struct kserdes_config *sc, u32 lane)
+{
+	FINSR(sc->regs, LANE_CTRL_STS_REG(lane), 31, 29, 0x4);
+	FINSR(sc->regs, LANE_CTRL_STS_REG(lane), 15, 13, 0x4);
+}
+
+static inline void _kserdes_lane_enable(void __iomem *sregs, u32 lane)
+{
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 31, 29, 0x7);
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 15, 13, 0x7);
+}
+
+/* Caller should make sure sgmii cannot be fullrate */
+static inline int _kserdes_set_lane_ctrl_rate(
+	void __iomem			*sregs,
+	u32				lane,
+	enum KSERDES_LANE_CTRL_RATE	lane_ctrl_rate)
+{
+	u32 rate_mode;
+
+	if (lane_ctrl_rate == KSERDES_FULL_RATE)
+		rate_mode = 0x4;
+	else if (lane_ctrl_rate == KSERDES_QUARTER_RATE)
+		rate_mode = 0x6;
+	else if (lane_ctrl_rate == KSERDES_HALF_RATE)
+		rate_mode = 0x5;
+	else
+		return -EINVAL;
+
+	/* Tx */
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 28, 26, rate_mode);
+	/* Rx */
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 12, 10, rate_mode);
+	return 0;
+}
+
+static inline void _kserdes_set_lane_loopback(
+	void __iomem			*sregs,
+	u32				lane,
+	enum KSERDES_LINK_RATE		link_rate)
+{
+	if (link_rate == KSERDES_LINK_RATE_10P3125G) {
+		FINSR(sregs, LANEX_REG(lane, 0x0), 7, 0, 0x4);
+		FINSR(sregs, LANEX_REG(lane, 0x4), 2, 1, 0x3);
+	} else {
+		FINSR(sregs, LANEX_REG(lane, 0x0), 31, 24, 0x40);
+	}
+}
+
+static void kserdes_set_lane_rate(struct kserdes_config *sc, u32 lane)
+{
+	int ret;
+
+	ret = _kserdes_set_lane_ctrl_rate(sc->regs, lane,
+					  sc->lane[lane].ctrl_rate);
+	if (ret) {
+		dev_err(sc->dev, "set_lane_rate FAILED: lane = %d err = %d\n",
+			lane, ret);
+		return;
+	}
+
+	/* disable attenuation auto scale */
+	FINSR(sc->regs, LANEX_REG(lane, 0x30), 11, 11, 0x1);
+	FINSR(sc->regs, LANEX_REG(lane, 0x30), 13, 12, 0x0);
+
+	/* set NES bit if loopback enabled */
+	if (sc->lane[lane].loopback)
+		_kserdes_set_lane_loopback(sc->regs, lane, sc->link_rate);
+
+	_kserdes_lane_enable(sc->regs, lane);
+}
+
+static inline void _kserdes_set_wait_after(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 17, 16, 0x3);
+}
+
+static inline void _kserdes_clear_wait_after(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 17, 16, 0);
+}
+
+static inline void _kserdes_pll_enable(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 31, 29, 0x7);
+}
+
+static inline void _kserdes_pll2_enable(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 27, 25, 0x7);
+}
+
+static inline void _kserdes_pll_disable(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 31, 29, 0x4);
+}
+
+static inline void _kserdes_pll2_disable(void __iomem *sregs)
+{
+	FINSR(sregs, PLL_CTRL_REG, 27, 25, 0x4);
+}
+
+static inline u32 _kserdes_get_pll_status(void __iomem *sregs)
+{
+	return FEXTR(kserdes_readl(sregs, PLL_CTRL_REG), 28, 28);
+}
+
+static inline u32 _kserdes_get_pll2_status(void __iomem *sregs)
+{
+	return FEXTR(kserdes_readl(sregs, PLL_CTRL_REG), 24, 24);
+}
+
+static inline void kserdes_lane_enable_loopback(void __iomem *serdes, u32 lane)
+{
+	FINSR(serdes, LANEX_REG(lane, 0), 31, 24, 0x40);
+}
+
+static inline u32 _kserdes_get_lane_status(
+		void __iomem		*sregs,
+		u32			lane,
+		enum KSERDES_PHY_TYPE	phy_type)
+{
+	if (phy_type == KSERDES_PHY_PCIE) {
+		return FEXTR(kserdes_readl(sregs, PLL_CTRL_REG), lane, lane);
+	} else if (phy_type == KSERDES_PHY_XGE) {
+		return FEXTR(kserdes_readl(sregs, CML_REG(0x1f8)),
+			     (29 + lane), (29 + lane));
+	} else {
+		return FEXTR(kserdes_readl(sregs, PLL_CTRL_REG),
+			     (8 + lane), (8 + lane));
+	}
+}
+
+static u32 kserdes_get_pll_lanes_status(struct kserdes_config *sc)
+{
+	u32 val, i;
+
+	/* Check PLL OK Status Bit */
+	val = _kserdes_get_pll_status(sc->regs);
+	if (!val) {
+		/* pll is not ready */
+		goto done;
+	}
+
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		val = _kserdes_get_pll2_status(sc->regs);
+		if (!val)
+			goto done;
+	}
+
+	/* Check Lane OK Status Bits */
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		val &= _kserdes_get_lane_status(sc->regs, i, sc->phy_type);
+	}
+
+done:
+	/* if any of the status is 0, this is 0
+	 * i.e. serdes status is not good
+	 */
+	return val;
+}
+
+int kserdes_get_status(struct kserdes_config *sc)
+{
+	unsigned long timeout;
+
+	/* is 500 msec a good number? */
+	timeout = jiffies + msecs_to_jiffies(500);
+	do {
+		if (kserdes_get_pll_lanes_status(sc))
+			break;
+
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+
+		cpu_relax();
+	} while (true);
+
+	return 0;
+}
+
+static inline u32 _kserdes_get_tx_termination(
+		void __iomem		*sregs,
+		enum KSERDES_PHY_TYPE	phy_type,
+		u32			lane)
+{
+	return (_kserdes_read_select_tbus(sregs, lane + 1,
+					  ((phy_type == KSERDES_PHY_XGE) ?
+					  0x1a : 0x1b)) & 0xff);
+}
+
+static void kserdes_set_tx_terminations(struct kserdes_config *sc, u32 term)
+{
+	u32 i;
+
+	for (i = 0; i < sc->lanes; i++) {
+		FINSR(sc->regs, LANEX_REG(i, 0x7c), 31, 24, term);
+		/* set termination override */
+		FINSR(sc->regs, LANEX_REG(i, 0x7c), 20, 20, 0x1);
+	}
+}
+
+/* lane is 0-based */
+static void
+_kserdes_get_cmp_tap_offsets_xge(void __iomem *sregs, u32 lane, u32 cmp,
+				 struct kserdes_comparator_tap_offsets *ofs)
+{
+	/* set comparator number */
+	FINSR(sregs, CML_REG(0x8c), 23, 21, cmp);
+
+	/* read offsets */
+	FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((lane + 2) << 8) + 0x11);
+	ofs->cmp = (_kserdes_read_tbus_val(sregs) & 0x0ff0) >> 4;
+
+	FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((lane + 2) << 8) + 0x11);
+	ofs->tap1 = (_kserdes_read_tbus_val(sregs) & 0x000f) << 3;
+
+	FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((lane + 2) << 8) + 0x12);
+	ofs->tap1 |= (_kserdes_read_tbus_val(sregs) & 0x0e00) >> 9;
+	ofs->tap2  = (_kserdes_read_tbus_val(sregs) & 0x01f8) >> 3;
+	ofs->tap3  = (_kserdes_read_tbus_val(sregs) & 0x0007) << 3;
+
+	FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((lane + 2) << 8) + 0x13);
+	ofs->tap3 |= (_kserdes_read_tbus_val(sregs) & 0x0e00) >> 9;
+	ofs->tap4  = (_kserdes_read_tbus_val(sregs) & 0x01f8) >> 3;
+	ofs->tap5  = (_kserdes_read_tbus_val(sregs) & 0x0007) << 3;
+
+	FINSR(sregs, CMU0_REG(0xfc), 26, 16, ((lane + 2) << 8) + 0x14);
+	ofs->tap5 |= (_kserdes_read_tbus_val(sregs) & 0x0e00) >> 9;
+}
+
+static void kserdes_add_offsets_xge(struct kserdes_config *sc,
+				    struct kserdes_offsets *sofs)
+{
+	struct kserdes_comparator_tap_offsets *ctofs;
+	struct kserdes_comparator_tap_offsets sample;
+	struct kserdes_lane_offsets *lofs;
+	u32 lane, cmp;
+
+	for (lane = 0; lane < sc->lanes; lane++) {
+		lofs = &sofs->lane_ofs[lane];
+		/* yes cmp starts from 1 */
+		for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+			ctofs = &lofs->ct_ofs[cmp];
+
+			_kserdes_get_cmp_tap_offsets_xge(sc->regs, lane,
+							 cmp, &sample);
+
+			ctofs->cmp  += sample.cmp;
+			ctofs->tap1 += sample.tap1;
+			ctofs->tap2 += sample.tap2;
+			ctofs->tap3 += sample.tap3;
+			ctofs->tap4 += sample.tap4;
+			ctofs->tap5 += sample.tap5;
+		}
+	}
+}
+
+/* lane is 0-based */
+static void
+kserdes_get_cmp_tap_offsets_non_xge(void __iomem *sregs, u32 lane, u32 cmp,
+				    struct kserdes_comparator_tap_offsets *ofs)
+{
+	/* set comparator number */
+	FINSR(sregs, CML_REG(0x8c), 23, 21, cmp);
+
+	/* read offsets */
+	FINSR(sregs, CMU0_REG(0x8), 31, 24, ((lane + 1) << 5) + 0x12);
+	ofs->cmp = (_kserdes_read_tbus_val(sregs) & 0x0ff0) >> 4;
+}
+
+static void kserdes_add_offsets_non_xge(struct kserdes_config *sc,
+					struct kserdes_offsets *sofs)
+{
+	struct kserdes_comparator_tap_offsets *ctofs;
+	struct kserdes_comparator_tap_offsets sample;
+	struct kserdes_lane_offsets *lofs;
+	u32 lane, cmp;
+
+	for (lane = 0; lane < sc->lanes; lane++) {
+		lofs = &sofs->lane_ofs[lane];
+		/* yes cmp starts from 1 */
+		for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+			ctofs = &lofs->ct_ofs[cmp];
+
+			kserdes_get_cmp_tap_offsets_non_xge(sc->regs, lane,
+							    cmp, &sample);
+
+			ctofs->cmp  += sample.cmp;
+		}
+	}
+}
+
+static void kserdes_get_average_offsets(struct kserdes_config *sc, u32 samples,
+					struct kserdes_offsets *sofs)
+{
+	struct kserdes_comparator_tap_offsets *ctofs;
+	struct kserdes_lane_offsets *lofs;
+	u32 i, lane, cmp;
+	int ret;
+
+	memset(sofs, 0, sizeof(*sofs));
+
+	/* get the total of each offset for specified number of samples */
+	for (i = 0; i < samples; i++) {
+		kserdes_assert_reset(sc);
+		ret = kserdes_deassert_reset(sc, 1);
+		if (ret) {
+			dev_err(sc->dev,
+				"kserdes_get_average_offsets: reset failed %d\n",
+				ret);
+			return;
+		}
+
+		if (sc->phy_type == KSERDES_PHY_XGE)
+			kserdes_add_offsets_xge(sc, sofs);
+		else
+			kserdes_add_offsets_non_xge(sc, sofs);
+	}
+
+	/* take the average */
+	for (lane = 0; lane < sc->lanes; lane++) {
+		lofs = &sofs->lane_ofs[lane];
+		/* yes cmp starts from 1 */
+		for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+			ctofs = &lofs->ct_ofs[cmp];
+			if (sc->phy_type == KSERDES_PHY_XGE) {
+				ctofs->cmp  /= samples;
+				ctofs->tap1 /= samples;
+				ctofs->tap2 /= samples;
+				ctofs->tap3 /= samples;
+				ctofs->tap4 /= samples;
+				ctofs->tap5 /= samples;
+			} else {
+				ctofs->cmp  /= samples;
+			}
+		}
+	}
+}
+
+static void
+_kserdes_override_cmp_tap_offsets(void __iomem *sregs, u32 lane, u32 cmp,
+				  struct kserdes_comparator_tap_offsets *ofs)
+{
+	/* set dfe_shadow_lane_sel */
+	FINSR(sregs, CML_REG(0xf0), 27, 26, (lane + 1));
+
+	/* set cmp_offset_ovr_en to 1 */
+	FINSR(sregs, CML_REG(0x98), 24, 24, 0x1);
+
+	/* set rxeq_ovr_en to 0x1 */
+	FINSR(sregs, LANEX_REG(lane, 0x2c), 2, 2, 0x1);
+
+	/* set rxeq_dfe_cmp_sel_ovr to comp_no */
+	FINSR(sregs, LANEX_REG(lane, 0x30), 7, 5, cmp);
+
+	/* set dfe_tap_ovr_en to 1 */
+	FINSR(sregs, LANEX_REG(lane, 0x5c), 31, 31, 0x1);
+
+	/* set cmp offset override */
+	FINSR(sregs, CML_REG(0x9c), 7, 0, ofs->cmp);
+	/* set tap offset overrides */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 30, 24, ofs->tap1);
+	FINSR(sregs, LANEX_REG(lane, 0x5c),  5,  0, ofs->tap2);
+	FINSR(sregs, LANEX_REG(lane, 0x5c), 13,  8, ofs->tap3);
+	FINSR(sregs, LANEX_REG(lane, 0x5c), 21, 16, ofs->tap4);
+	FINSR(sregs, LANEX_REG(lane, 0x5c), 29, 24, ofs->tap5);
+
+	/* set rxeq_ovr_latch_o = 0x1 */
+	FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x1);
+	/* set rxeq_ovr_latch_o = 0x0 */
+	FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x0);
+
+	/* set cmp_offset_ovr_en to 0 */
+	FINSR(sregs, CML_REG(0x98), 24, 24, 0x0);
+	/* set rxeq_ovr_en to 0x0 */
+	FINSR(sregs, LANEX_REG(lane, 0x2c), 2, 2, 0x0);
+	/* set dfe_tap_ovr_en to 0 */
+	FINSR(sregs, LANEX_REG(lane, 0x5c), 31, 31, 0x0);
+}
+
+static inline void
+_kserdes_override_cmp_offset_cdfe(void __iomem *sregs, u32 lane,
+				  u32 cmp, u32 cmp_offset)
+{
+	/* enable comparator offset calibrate */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 18, 18, 0x1);
+
+	/* set gcfsm sel override to comparator */
+	FINSR(sregs, LANEX_REG(lane, 0x4c), 5, 2, (0x1 << (cmp - 1)));
+	/* set comparator offset */
+	FINSR(sregs, LANEX_REG(lane, 0x48), 24, 17, cmp_offset);
+	/* latch in value */
+	FINSR(sregs, LANEX_REG(lane, 0x48), 29, 29, 0x1);
+	FINSR(sregs, LANEX_REG(lane, 0x48), 29, 29, 0x0);
+
+	/* disable comparator offset calibrate */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 18, 18, 0x0);
+}
+
+static inline void
+_kserdes_override_tap_offset_cdfe(void __iomem *sregs, u32 lane,
+				  u32 tap, u32 width, u32 tap_offset)
+{
+	/* enable tap */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 23, 19, BIT(tap - 1));
+	/* set tap offset */
+	FINSR(sregs, LANEX_REG(lane, 0x48), 17 + (width - 1), 17, tap_offset);
+	/* latch in value */
+	FINSR(sregs, LANEX_REG(lane, 0x48), 29, 29, 0x1);
+	FINSR(sregs, LANEX_REG(lane, 0x48), 29, 29, 0x0);
+}
+
+static void _kserdes_override_cmp_tap_offsets_cdfe(
+	void __iomem				*sregs,
+	u32					lane,
+	u32					cmp,
+	struct kserdes_comparator_tap_offsets	*ofs)
+{
+	/* enable overrides */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 16, 16, 0x1);
+	FINSR(sregs, LANEX_REG(lane, 0x48), 16, 16, 0x1);
+
+	_kserdes_override_cmp_offset_cdfe(sregs, lane, cmp, ofs->cmp);
+
+	/* enable tap offset calibrate */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 17, 17, 0x1);
+
+	/* set tap offsets */
+	_kserdes_override_tap_offset_cdfe(sregs, lane, 1, 7, ofs->tap1);
+	_kserdes_override_tap_offset_cdfe(sregs, lane, 2, 6, ofs->tap2);
+	_kserdes_override_tap_offset_cdfe(sregs, lane, 3, 6, ofs->tap3);
+	_kserdes_override_tap_offset_cdfe(sregs, lane, 4, 6, ofs->tap4);
+	_kserdes_override_tap_offset_cdfe(sregs, lane, 5, 6, ofs->tap5);
+
+	/* disable overrides */
+	FINSR(sregs, LANEX_REG(lane, 0x58), 16, 16, 0x0);
+	FINSR(sregs, LANEX_REG(lane, 0x48), 16, 16, 0x0);
+	FINSR(sregs, LANEX_REG(lane, 0x58), 18, 18, 0x0);
+	FINSR(sregs, LANEX_REG(lane, 0x58), 17, 17, 0x0);
+}
+
+static void kserdes_set_offsets_xge(struct kserdes_config *sc,
+				    struct kserdes_offsets *sofs)
+{
+	struct kserdes_comparator_tap_offsets *ctofs;
+	struct kserdes_lane_offsets *lofs;
+	u32 lane, cmp;
+
+	for (lane = 0; lane < sc->lanes; lane++) {
+		lofs = &sofs->lane_ofs[lane];
+		for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+			ctofs = &lofs->ct_ofs[cmp];
+			_kserdes_override_cmp_tap_offsets(sc->regs, lane,
+							  cmp, ctofs);
+			_kserdes_override_cmp_tap_offsets_cdfe(sc->regs, lane,
+							       cmp, ctofs);
+		}
+	}
+}
+
+static void kserdes_set_offsets_non_xge(struct kserdes_config *sc,
+					struct kserdes_offsets *sofs)
+{
+	struct kserdes_comparator_tap_offsets *ctofs;
+	struct kserdes_lane_offsets *lofs;
+	u32 lane, cmp;
+
+	for (lane = 0; lane < sc->lanes; lane++) {
+		lofs = &sofs->lane_ofs[lane];
+		for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+			ctofs = &lofs->ct_ofs[cmp];
+			_kserdes_override_cmp_tap_offsets(sc->regs, lane,
+							  cmp, ctofs);
+		}
+	}
+}
+
+static void kserdes_set_offsets(struct kserdes_config *sc,
+				struct kserdes_offsets *sofs)
+{
+	if (sc->phy_type == KSERDES_PHY_XGE)
+		kserdes_set_offsets_xge(sc, sofs);
+	else
+		kserdes_set_offsets_non_xge(sc, sofs);
+}
+
+static void kserdes_dfe_offset_calibration(struct kserdes_config *sc,
+					   struct kserdes_offsets *sofs)
+{
+	for_each_enable_lane(kserdes_force_signal_detect_low, sc);
+	usleep_range(10, 20);
+
+	/* offset compensation patch */
+	kserdes_get_average_offsets(sc, DFE_OFFSET_SAMPLES, sofs);
+	kserdes_set_offsets(sc, sofs);
+	usleep_range(10, 20);
+
+	/* re-acquire signal detect */
+	for_each_lane(kserdes_force_signal_detect_high, sc);
+	usleep_range(10, 20);
+}
+
+static void kserdes_override_tap_offsets(struct kserdes_config *sc, u32 lane)
+{
+	u32 tap1val, tap2val, tap3val, tap4val, tap5val;
+	void __iomem *sregs = sc->regs;
+	u32 cmp, tap1_ofs;
+
+	for (cmp = 1; cmp < MAX_COMPARATORS; cmp++) {
+		/* adjust taps only for center comparators of
+		 * of conparator 1 and 3
+		 */
+		if (!(cmp & 0x1))
+			continue;
+
+		/* set comparator number */
+		FINSR(sregs, CML_REG(0x8c), 23, 21, cmp);
+
+		/* read offsets */
+		FINSR(sregs, CMU0_REG(0x8), 31, 24, ((lane + 1) << 5) + 0x12);
+		tap1_ofs = (_kserdes_read_tbus_val(sregs) & 0x000f) << 3;
+
+		FINSR(sregs, CMU0_REG(0x8), 31, 24, ((lane + 1) << 5) + 0x13);
+		tap1_ofs |= (_kserdes_read_tbus_val(sregs) & 0x0e00) >> 9;
+
+		tap1val = tap1_ofs - 14;
+		tap2val = 31;
+		tap3val = 31;
+		tap4val = 31;
+		tap5val = 31;
+
+		/* set dfe_shadow_lane_sel */
+		FINSR(sregs, CML_REG(0xf0), 27, 26, lane + 1);
+		/* Set rxeq_ovr_en to 0x1 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 2, 2, 0x1);
+		/* set rxeq_dfe_cmp_sel_ovr to comp_no */
+		FINSR(sregs, LANEX_REG(lane, 0x30), 7, 5, cmp);
+		/* set dfe_tap_ovr_en to 1 */
+		FINSR(sregs, LANEX_REG(lane, 0x5c), 31, 31, 0x1);
+
+		/* set tap overrides */
+		FINSR(sregs, LANEX_REG(lane, 0x58), 30, 24, tap1val);
+		FINSR(sregs, LANEX_REG(lane, 0x5c),  6,  0, tap2val);
+		FINSR(sregs, LANEX_REG(lane, 0x5c), 13,  8, tap3val);
+		FINSR(sregs, LANEX_REG(lane, 0x5c), 21, 16, tap4val);
+		FINSR(sregs, LANEX_REG(lane, 0x5c), 29, 24, tap5val);
+
+		/* set rxeq_ovr_latch_o = 0x1 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x1);
+		/* set rxeq_ovr_latch_o = 0x0 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x0);
+
+		/* set rxeq_ovr_en to 0 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 2, 2, 0x0);
+		/* set dfe_tap_ovr_en to 0 */
+		FINSR(sregs, LANEX_REG(lane, 0x5c), 31, 31, 0x0);
+
+		/* This part of code will latch in offsets to
+		 * tap adaptation logic so that if adaptation
+		 * occurs, it will pick these offsets
+		 */
+		/* enable overrides */
+		FINSR(sregs, LANEX_REG(lane, 0x58), 16, 16, 0x1);
+		FINSR(sregs, LANEX_REG(lane, 0x48), 16, 16, 0x1);
+
+		/* set gcfsm_cmp_sel to comp_no */
+		FINSR(sregs, LANEX_REG(lane, 0x4c), 5, 2, (0x1 << (cmp - 1)));
+		/* enable tap offset calibrate */
+		FINSR(sregs, LANEX_REG(lane, 0x58), 17, 17, 0x1);
+
+		/* enable taps */
+		_kserdes_override_tap_offset_cdfe(sregs, lane, 1, 7, tap1val);
+		_kserdes_override_tap_offset_cdfe(sregs, lane, 2, 6, tap2val);
+		_kserdes_override_tap_offset_cdfe(sregs, lane, 3, 6, tap3val);
+		_kserdes_override_tap_offset_cdfe(sregs, lane, 4, 6, tap4val);
+		_kserdes_override_tap_offset_cdfe(sregs, lane, 5, 6, tap5val);
+
+		/* Disable overrides */
+		FINSR(sregs, LANEX_REG(lane, 0x58), 16, 16, 0x0);
+		FINSR(sregs, LANEX_REG(lane, 0x48), 16, 16, 0x0);
+		FINSR(sregs, LANEX_REG(lane, 0x58), 17, 17, 0x0);
+	}
+}
+
+static int kserdes_wait_lane_rx_valid(struct kserdes_config *sc, u32 lane)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(500);
+	u32 status;
+
+	do {
+		status = _kserdes_read_select_tbus(sc->regs, lane + 1, 0x02);
+
+		if (status & 0x20)
+			return 0;
+
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+
+		cpu_relax();
+	} while (true);
+}
+
+static int kserdes_att_boost_phya_macro_patch(struct kserdes_config *sc)
+{
+	u32 i, att_read[KSERDES_MAX_LANES], att_start[KSERDES_MAX_LANES];
+	int ret;
+
+	/* First save a copy of initial att start value */
+	for (i = 0; i < sc->lanes; i++) {
+		att_start[i] = kserdes_readl(sc->regs, LANEX_REG(i, 0x8c));
+		att_start[i] = (att_start[i] >> 8) & 0xf;
+	}
+	/* Get att and fix this as start value.  Turn off att adaptation and
+	 * do boost readaptation
+	 */
+	for (i = 0; i < sc->lanes; i++) {
+		att_read[i] = _kserdes_read_select_tbus(
+					sc->regs, i + 1,
+					(sc->phy_type == KSERDES_PHY_XGE) ?
+					0x10 : 0x11);
+		att_read[i] = (att_read[i] >> 4) & 0xf;
+	}
+	for (i = 0; i < sc->lanes; i++) {
+		/* att start */
+		FINSR(sc->regs, LANEX_REG(i, 0x8c), 11, 8, att_read[i]);
+	}
+	/* clear att init calibration */
+	FINSR(sc->regs, CML_REG(0x84), 0, 0, 0x0);
+	/* clear att re-calibration */
+	FINSR(sc->regs, CML_REG(0x8c), 24, 24, 0x0);
+
+	/* force calibration on all lanes */
+	/* set att continuous recal */
+	FINSR(sc->regs, CML_REG(0x98), 7, 7, 0x1);
+	/* clear att continuous recal */
+	FINSR(sc->regs, CML_REG(0x98), 7, 7, 0x0);
+	usleep_range(300, 400);
+
+	/* check rx valid */
+	for_each_enable_lane_return(kserdes_wait_lane_rx_valid, sc, ret);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_wait_lane_rx_valid FAILED %d\n", ret);
+		return ret;
+	}
+
+	/* write back initial att start value */
+	for (i = 0; i < sc->lanes; i++)
+		FINSR(sc->regs, LANEX_REG(i, 0x8c), 11, 8, att_start[i]);
+
+	/* turn att adaptation back on */
+	FINSR(sc->regs, CML_REG(0x84),  0,  0, 0x1);
+	FINSR(sc->regs, CML_REG(0x8c), 24, 24, 0x1);
+
+	return 0;
+}
+
+static int kserdes_att_boost_phya_lane_patch(struct kserdes_config *sc,
+					     u32 lane)
+{
+	u32 boost_read;
+	int ret;
+
+	/* check lane rx valid */
+	ret = kserdes_wait_lane_rx_valid(sc, lane);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_wait_lane_rx_valid FAILED %d\n", ret);
+		return ret;
+	}
+
+	/* check boost value */
+	boost_read = _kserdes_read_select_tbus(
+				sc->regs, lane + 1,
+				(sc->phy_type == KSERDES_PHY_XGE) ?
+				0x10 : 0x11);
+	boost_read = (boost_read >> 8) & 0xf;
+
+	/* increment boost by 1 if it's 0 */
+	if (!boost_read) {
+		/* Set rxeq_ovr_en to 1 */
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c),  2,  2, 0x1);
+		/* set rxeq_ovr_load_en for boost only */
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c), 18, 12, 0x2);
+		/* set rxeq_ovr_load for a value of 1 */
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c),  9,  3, 0x1);
+		/* latch in new boost value */
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c), 10, 10, 0x1);
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c), 10, 10, 0x0);
+		/* reset previous registers */
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c),  2,  2, 0x0);
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c), 18, 12, 0x0);
+		FINSR(sc->regs, LANEX_REG(lane, 0x2c),  9,  3, 0x0);
+	}
+	return 0;
+}
+
+static inline void kserdes_att_boost_phya_patch(struct kserdes_config *sc)
+{
+	kserdes_att_boost_phya_macro_patch(sc);
+
+	for_each_enable_lane(kserdes_att_boost_phya_lane_patch, sc);
+}
+
+static void kserdes_att_boost_phyb_lane_patch(struct kserdes_config *sc,
+					      u32 lane)
+{
+	u32 tbus_ofs, rxeq_init_reg_ofs, rxeq_ln_reg_ofs, rxeq_ln_force_bit;
+	void __iomem *sregs = sc->regs;
+	u32 att_start, att_read, boost_read;
+	int ret;
+
+	/* some setups */
+	if (sc->phy_type == KSERDES_PHY_XGE) {
+		tbus_ofs = 0x10;
+		rxeq_init_reg_ofs = 0x9c;
+		rxeq_ln_reg_ofs = 0x98;
+		rxeq_ln_force_bit = 14;
+	} else {
+		tbus_ofs = 0x11;
+		rxeq_init_reg_ofs = 0x84;
+		rxeq_ln_reg_ofs = 0xac;
+		rxeq_ln_force_bit = 11;
+	}
+
+	/* First save a copy of initial att start value */
+	att_start = kserdes_readl(sregs, LANEX_REG(lane, 0x8c));
+	att_start = (att_start >> 8) & 0xf;
+
+	/* Get att and fix this as start value.  Turn off att adaptation and
+	 * do boost readaptation
+	 */
+	att_read = _kserdes_read_select_tbus(sregs, lane + 1, tbus_ofs);
+	att_read = (att_read >> 4) & 0xf;
+
+	/* att start */
+	FINSR(sregs, LANEX_REG(lane, 0x8c), 11, 8, att_read);
+	/* clear att init calibration */
+	FINSR(sregs, LANEX_REG(lane, rxeq_init_reg_ofs), 0, 0, 0x0);
+	/* clear att re-calibration */
+	FINSR(sregs, CML_REG(0x8c), 24, 24, 0x0);
+
+	/* force calibration */
+	FINSR(sregs, LANEX_REG(lane, rxeq_ln_reg_ofs),
+	      rxeq_ln_force_bit, rxeq_ln_force_bit, 0x1);
+	FINSR(sregs, LANEX_REG(lane, rxeq_ln_reg_ofs),
+	      rxeq_ln_force_bit, rxeq_ln_force_bit, 0x0);
+
+	/* check lane rx valid */
+	ret = kserdes_wait_lane_rx_valid(sc, lane);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_wait_lane_rx_valid %d FAILED: %d\n",
+			lane, ret);
+	}
+	usleep_range(300, 400);
+
+	/* check boost value */
+	boost_read = _kserdes_read_select_tbus(sregs, lane + 1, tbus_ofs);
+	boost_read = (boost_read >> 8) & 0xf;
+
+	/* increment boost by 1 if it's 0 */
+	if (!boost_read) {
+		/* Set rxeq_ovr_en to 1 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c),  2,  2, 0x1);
+		/* set rxeq_ovr_load_en for boost only */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 18, 12, 0x2);
+		/* set rxeq_ovr_load for a value of 1 */
+		FINSR(sregs, LANEX_REG(lane, 0x2c),  9,  3, 0x1);
+		/* latch in new boost value */
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x1);
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 10, 10, 0x0);
+		/* reset previous registers */
+		FINSR(sregs, LANEX_REG(lane, 0x2c),  2,  2, 0x0);
+		FINSR(sregs, LANEX_REG(lane, 0x2c), 18, 12, 0x0);
+		FINSR(sregs, LANEX_REG(lane, 0x2c),  9,  3, 0x0);
+	}
+
+	/* write back initial att start value */
+	FINSR(sregs, LANEX_REG(lane, 0x8c), 11, 8, att_start);
+	/* turn att adaptation back on */
+	FINSR(sregs, LANEX_REG(lane, rxeq_init_reg_ofs), 0, 0, 0x1);
+	FINSR(sregs, CML_REG(0x8c), 24, 24, 0x1);
+}
+
+static inline void kserdes_att_boost_phyb_patch(struct kserdes_config *sc,
+						u32 lane)
+{
+	kserdes_att_boost_phyb_lane_patch(sc, lane);
+}
+
+static void kserdes_att_boost_phy_patch(struct kserdes_config *sc)
+{
+	if (sc->phy_type != KSERDES_PHY_XGE)
+		kserdes_att_boost_phya_patch(sc);
+	else
+		for_each_lane(kserdes_att_boost_phyb_patch, sc);
+}
+
+int kserdes_sgmii_lanes_enable(struct kserdes_config *sc)
+{
+	int ret, i;
+	u32 val, lanes_enable = 0;
+
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		lanes_enable |= (1 << i);
+	}
+
+	/* configure Tap 1 if PHY-A and link rate greater than 8Gbaud */
+	if (sc->link_rate >= KSERDES_LINK_RATE_9P8304G)
+		kserdes_tap1_patch(sc);
+
+	/* disable transmitter on all lanes to prevent
+	 * receiver from adapting
+	 */
+	for_each_lane(kserdes_set_tx_idle, sc);
+
+	/* apply patch for link rates greater than 8Gbaud */
+	kserdes_phy_patch(sc);
+
+	/* write boost training pattern for Hyperlink functional mode */
+	if (sc->phy_type == KSERDES_PHY_HYPERLINK)
+		_kserdes_set_training_pattern(sc->regs);
+
+	/* assert serdes reset */
+	kserdes_assert_reset(sc);
+
+	/* apply the TX and RX FIR coefficients to the lanes */
+	for_each_enable_lane(kserdes_set_tx_rx_fir_coeff, sc);
+
+	/* force Signal Detect Low. This resets the CDR,
+	 * Attenuation and Boost circuitry
+	 */
+	for_each_enable_lane(kserdes_force_signal_detect_low, sc);
+
+	ret = kserdes_deassert_reset(sc, 0);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_deassert_reset FAILED %d\n", ret);
+		return ret;
+	}
+
+	/* allow signal detect enable */
+	for_each_enable_lane(kserdes_set_lane_rate, sc);
+
+	_kserdes_pll_enable(sc->regs);
+
+	ret = kserdes_get_status(sc);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_get_status FAILED %d\n", ret);
+		return ret;
+	}
+
+	/* get tx termination on lane 0 */
+	val = _kserdes_get_tx_termination(sc->regs, sc->phy_type, 0);
+
+	/* apply tx termination to all lanes */
+	kserdes_set_tx_terminations(sc, val);
+
+	if (sc->link_rate >= KSERDES_LINK_RATE_9P8304G) {
+		/* manually adjust Tap 1 value for phy-a > 8GBaud */
+		for_each_enable_lane(kserdes_override_tap_offsets, sc);
+	}
+
+	/* We are always in FUNCTIONAL mode, so we always
+	 * continue to the following.
+	 */
+	/* enable transmitter on all lanes */
+	for_each_enable_lane(kserdes_clr_tx_idle, sc);
+
+	/* allow Signal Detect Enable */
+	for_each_enable_lane(kserdes_force_signal_detect_high, sc);
+
+	/* Wait for RX Valid on all lanes */
+	for_each_enable_lane_return(kserdes_wait_lane_rx_valid, sc, ret);
+	if (ret) {
+		dev_err(sc->dev, "kserdes_wait_lane_rx_valid FAILED %d\n", ret);
+		return ret;
+	}
+
+	/* Apply Attenuation and Boost Patch if rx force
+	 * flag is set
+	 */
+	if (!sc->rx_force_enable)
+		kserdes_att_boost_phy_patch(sc);
+
+	/* If needed, check for errors or see if DLPF is
+	 * railing and toggle signal detect
+	 */
+	/* CSL_Serdes_CDR_Reset(); */
+
+	/* Enable MAC RX to allow MAC to take control */
+	_kserdes_clear_wait_after(sc->regs);
+
+	return lanes_enable;
+}
+
+static int kserdes_sgmii_init(struct kserdes_config *sc)
+{
+	return kserdes_load_init_fw(sc, ks2_gbe_serdes_firmwares,
+				    ARRAY_SIZE(ks2_gbe_serdes_firmwares));
+}
+
+static inline void _kserdes_set_link_loss_wait(void __iomem *sregs,
+					       u32 link_loss_wait)
+{
+	kserdes_writel(sregs, LINK_LOSS_WAIT_REG, link_loss_wait);
+}
+
+static inline void _kserdes_reset(void __iomem *sregs)
+{
+	/* Toggle POR_EN bit */
+	FINSR(sregs, CPU_CTRL_REG, 29, 29, 0x1);
+	usleep_range(10, 20);
+	FINSR(sregs, CPU_CTRL_REG, 29, 29, 0x0);
+	usleep_range(10, 20);
+}
+
+static inline void kserdes_xge_pll_enable(struct kserdes_config *sc)
+{
+	/* phyb reset clear */
+	if (!sc->firmware)
+		FINSR(sc->regs, CML_REG(0), 7, 0, 0x1f);
+
+	if (sc->link_rate == KSERDES_LINK_RATE_10P3125G) {
+		_kserdes_pll_enable(sc->regs);
+		_kserdes_pll2_enable(sc->regs);
+	} else if (sc->link_rate == KSERDES_LINK_RATE_1P25G) {
+		kserdes_writel(sc->regs, PLL_CTRL_REG, 0xe0000000);
+	}
+}
+
+static inline void _kserdes_xge_enable_pcs(void __iomem *sregs, u32 lane)
+{
+	/* set bus-width to 16 bit mode */
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 23, 21, 0x7);
+	FINSR(sregs, LANE_CTRL_STS_REG(lane),  5,  3, 0x7);
+
+	/* enable PCS overlay and lane select 10GKR */
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 16, 16, 0x1);
+	FINSR(sregs, LANE_CTRL_STS_REG(lane), 19, 19, 0x1);
+}
+
+static inline void kserdes_xge_lane_enable(struct kserdes_config *sc, u32 lane)
+{
+	u32 lane_ctrl_rate = sc->lane[lane].ctrl_rate;
+
+	/* Set Lane Control Rate */
+	if (sc->link_rate == KSERDES_LINK_RATE_10P3125G)
+		_kserdes_set_lane_ctrl_rate(sc->regs, lane, lane_ctrl_rate);
+	else if (sc->link_rate == KSERDES_LINK_RATE_1P25G)
+		kserdes_writel(sc->regs, LANE_CTRL_STS_REG(lane), 0xf800f8c0);
+
+	_kserdes_xge_enable_pcs(sc->regs, lane);
+
+	_kserdes_lane_enable(sc->regs, lane);
+
+	if (sc->lane[lane].loopback)
+		_kserdes_set_lane_loopback(sc->regs, lane, sc->link_rate);
+}
+
+static inline void _kserdes_enable_xgmii_port(struct regmap *peripheral_regmap,
+					      u32 port)
+{
+	regmap_update_bits(peripheral_regmap, XGE_CTRL_OFFSET,
+			   GENMASK(port, port), BIT(port));
+}
+
+static inline void _kserdes_reset_cdr(void __iomem *sregs, int lane)
+{
+	/* toggle signal detect */
+	_kserdes_force_signal_detect_low(sregs, lane);
+	mdelay(1);
+	_kserdes_force_signal_detect_high(sregs, lane);
+}
+
+/* Call every 10 ms */
+static int
+_kserdes_check_link_status(struct device *dev, void __iomem *sregs,
+			   struct regmap *pcsr_regmap, u32 lanes,
+			   u32 lanes_enable, u32 *current_state, u32 *lane_down)
+{
+	u32 pcsr_rx_stat, blk_lock, blk_errs;
+	int loss, i, status = 1;
+	int ret;
+
+	for (i = 0; i < lanes; i++) {
+		if (!(lanes_enable & (1 << i)))
+			continue;
+
+		/* Rx Signal Loss bit in serdes lane control and status reg*/
+		loss = (kserdes_readl(sregs, LANE_CTRL_STS_REG(i))) & 0x01;
+
+		/* Block Errors and Block Lock bits in PCSR rx status reg */
+		ret = regmap_read(pcsr_regmap, PCSR_RX_STATUS(i),
+				  &pcsr_rx_stat);
+
+		if (ret)
+			return ret;
+
+		blk_lock = (pcsr_rx_stat >> 30) & 0x1;
+		blk_errs = (pcsr_rx_stat >> 16) & 0x0ff;
+
+		/* If Block error, attempt recovery! */
+		if (blk_errs)
+			blk_lock = 0;
+
+		switch (current_state[i]) {
+		case 0:
+			/* if good link lock the signal detect ON! */
+			if (!loss && blk_lock) {
+				dev_dbg(dev, "XGE PCSR Linked Lane: %d\n", i);
+				FINSR(sregs, LANEX_REG(i, 0x04), 2, 1, 0x3);
+				current_state[i] = 1;
+			} else {
+				/* if no lock, then reset CDR
+				 * by toggling sig detect
+				 */
+				if (!blk_lock) {
+					dev_dbg(dev,
+						"XGE PCSR Recover Lane: %d\n",
+						i);
+
+					_kserdes_reset_cdr(sregs, i);
+				}
+			}
+			break;
+		case 1:
+			if (!blk_lock) {
+				/* Link Lost? */
+				lane_down[i] = 1;
+				current_state[i] = 2;
+			}
+			break;
+		case 2:
+			if (blk_lock)
+				/* Nope just noise */
+				current_state[i] = 1;
+			else {
+				/* Lost the block lock, reset CDR if it is
+				 * not centered and go back to sync state
+				 */
+				_kserdes_reset_cdr(sregs, i);
+
+				current_state[i] = 0;
+			}
+			break;
+		default:
+			dev_info(dev, "XGE: unknown current_state[%d] %d\n",
+				 i, current_state[i]);
+			break;
+		}
+
+		if (blk_errs) {
+			/* Reset the Error counts! */
+			regmap_update_bits(pcsr_regmap, PCSR_RX_CTL(i),
+					   GENMASK(7, 0), 0x19);
+			regmap_update_bits(pcsr_regmap, PCSR_RX_CTL(i),
+					   GENMASK(7, 0), 0x00);
+		}
+
+		status &= (current_state[i] == 1);
+	}
+
+	return status;
+}
+
+static int _kserdes_wait_link_up(struct device *dev, void __iomem *sregs,
+				 struct regmap *pcsr_regmap,
+				 u32 lanes, u32 lanes_enable)
+{
+	u32 current_state[KSERDES_MAX_LANES];
+	int retries = 0, link_up;
+	u32 lane_down[KSERDES_MAX_LANES];
+	int i;
+
+	if (lanes > KSERDES_MAX_LANES)
+		return -EINVAL;
+
+	memset(current_state, 0, sizeof(current_state));
+	memset(lane_down, 0, sizeof(lane_down));
+
+	do {
+		mdelay(10);
+		memset(lane_down, 0, sizeof(lane_down));
+
+		link_up = _kserdes_check_link_status(dev, sregs,
+						     pcsr_regmap, lanes,
+						     lanes_enable,
+						     current_state, lane_down);
+
+		/* if we did not get link up then wait 100ms
+		 * before calling it again
+		 */
+		if (link_up)
+			break;
+
+		for (i = 0; i < lanes; i++) {
+			if ((lanes_enable & (1 << i)) && lane_down[i])
+				dev_dbg(dev,
+					"XGE: detected lane down on lane %d\n",
+					i);
+		}
+
+		if (++retries > 100)
+			return -ETIMEDOUT;
+
+	} while (!link_up);
+
+	dev_info(dev, "XGE: serdes link up: retried %d times\n", retries);
+	return 0;
+}
+
+static int kserdes_xge_lanes_enable(struct kserdes_config *sc)
+{
+	struct kserdes_offsets sofs;
+	int ret, i;
+	u32 lanes_enable = 0;
+
+	if (sc->firmware) {
+		/* firmware started in serdes_init and
+		 * doesn't need lanes enable
+		 */
+		return 0;
+	}
+
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		lanes_enable |= (1 << i);
+	}
+
+	kserdes_phy_patch(sc);
+	kserdes_xge_pll_enable(sc);
+
+	for_each_lane(kserdes_xge_lane_enable, sc);
+
+	ret = kserdes_get_status(sc);
+	if (ret) {
+		dev_err(sc->dev,
+			"kserdes_xge_lanes_enable get status FAILED %d\n", ret);
+		return ret;
+	}
+
+	kserdes_dfe_offset_calibration(sc, &sofs);
+
+	for (i = 0; i < sc->lanes; i++)
+		_kserdes_enable_xgmii_port(sc->peripheral_regmap, i);
+
+	_kserdes_wait_link_up(sc->dev, sc->regs, sc->pcsr_regmap,
+			      sc->lanes, lanes_enable);
+
+	return lanes_enable;
+}
+
+static inline void kserdes_xfw_get_lane_params(struct kserdes_config *sc,
+					       int lane)
+{
+	struct kserdes_fw_config *fw = &sc->fw;
+	u32 tx_ctrl, val_0, val_1;
+	u32 phy_a = PHY_A(sc->regs);
+
+	val_0 = kserdes_readl(sc->regs, LANEX_REG(lane, 0x04));
+	val_1 = kserdes_readl(sc->regs, LANEX_REG(lane, 0x08));
+
+	tx_ctrl = ((((val_0 >> 18) & 0x1)    << 24) |	/* TX_CTRL_O_24 */
+		   (((val_1 >> 0)  & 0xffff) <<  8) |	/* TX_CTRL_O_23_8 */
+		   (((val_0 >> 24) & 0xff)   <<  0));	/* TX_CTRL_O_7_0 */
+
+	if (phy_a) {
+		fw->cm = (val_1 >> 12) & 0xf;
+		fw->c1 = (val_1 >> 0) & 0x1f;
+		fw->c2 = (val_1 >> 8) & 0xf;
+	} else {
+		fw->cm = (tx_ctrl >> 16) & 0xf;
+		fw->c1 = (tx_ctrl >> 8) & 0x1f;
+		fw->c2 = (tx_ctrl >> 13) & 0x7;
+		fw->c2 = fw->c2 | (((tx_ctrl >> 24) & 0x1) << 3);
+	}
+
+	val_0 = _kserdes_read_select_tbus(sc->regs, lane + 1,
+					  (phy_a ? 0x11 : 0x10));
+	fw->attn = (val_0 >> 4) & 0xf;
+	fw->boost = (val_0 >> 8) & 0xf;
+
+	val_0 = _kserdes_read_select_tbus(sc->regs, lane + 1, 0x5);
+	fw->dlpf = (val_0 >> 2) & 0x3ff;
+
+	val_0 = _kserdes_read_select_tbus(sc->regs, lane + 1, 0x6);
+	fw->cdrcal = (val_0 >> 3) & 0xff;
+}
+
+static inline void kserdes_xfw_mem_init(struct kserdes_config *sc)
+{
+	struct kserdes_fw_config *fw = &sc->fw;
+	u32 i, lane_config = 0, lanes = sc->lanes;
+
+	for (i = 0; i < lanes; i++)
+		lane_config = (lane_config << 8) |
+			(fw->lane_config[i] & 0xff);
+
+	lane_config <<= 8;
+
+	/* initialize internal parameter area */
+	kserdes_writel(sc->regs, MEM_ADR_REG, KSERDES_XFW_CONFIG_START_ADDR);
+
+	/* clean out unused config area */
+	for (i = KSERDES_XFW_CONFIG_START_ADDR;
+	     i < KSERDES_XFW_PARAM_START_ADDR; i += 4)
+		kserdes_writel(sc->regs, MEM_DATINC_REG, 0x00000000);
+
+	/* Flush 64 bytes 10,11,12,13 */
+	kserdes_writel(sc->regs, MEM_DATINC_REG, 0x00009C9C);
+
+	/* fast train */
+	kserdes_writel(sc->regs, MEM_DATINC_REG, fw->fast_train);
+
+	kserdes_writel(sc->regs, MEM_DATINC_REG, 0x00000000);
+	/* lane seeds */
+	kserdes_writel(sc->regs, MEM_DATINC_REG, fw->lane_seeds);
+	/* lane config */
+	kserdes_writel(sc->regs, MEM_DATINC_REG, lane_config);
+}
+
+static int kserdes_xge_init(struct kserdes_config *sc)
+{
+	return kserdes_load_init_fw(sc, ks2_xgbe_serdes_firmwares,
+				    ARRAY_SIZE(ks2_xgbe_serdes_firmwares));
+}
+
+static int kserdes_pcie_lanes_enable(struct kserdes_config *sc)
+{
+	int ret, i;
+	u32 lanes_enable = 0;
+
+	for (i = 0; i < sc->lanes; i++) {
+		if (!LANE_ENABLE(sc, i))
+			continue;
+
+		lanes_enable |= (1 << i);
+	}
+
+	for (i = 0; i < sc->lanes; i++) {
+		kserdes_release_reset(sc, i);
+
+		if (sc->lane[i].loopback)
+			_kserdes_set_lane_loopback(sc->regs, i, sc->link_rate);
+	}
+
+	ret = kserdes_get_status(sc);
+	if (ret)
+		return ret;
+	else
+		return lanes_enable;
+}
+
+static int kserdes_pcie_init(struct kserdes_config *sc)
+{
+	return kserdes_load_init_fw(sc, ks2_pcie_serdes_firmwares,
+				    ARRAY_SIZE(ks2_pcie_serdes_firmwares));
+}
+
+static int kserdes_lanes_enable(struct kserdes_config *sc)
+{
+	switch (sc->phy_type) {
+	case KSERDES_PHY_SGMII:
+		return kserdes_sgmii_lanes_enable(sc);
+	case KSERDES_PHY_XGE:
+		return kserdes_xge_lanes_enable(sc);
+	case KSERDES_PHY_PCIE:
+		return kserdes_pcie_lanes_enable(sc);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int kserdes_init(struct phy *phy)
+{
+	struct kserdes_dev *sd = phy_get_drvdata(phy);
+	struct kserdes_config *sc = &sd->sc;
+	int ret;
+
+	switch (sc->phy_type) {
+	case KSERDES_PHY_SGMII:
+		ret = kserdes_sgmii_init(sc);
+		break;
+	case KSERDES_PHY_XGE:
+		ret = kserdes_xge_init(sc);
+		break;
+	case KSERDES_PHY_PCIE:
+		ret = kserdes_pcie_init(sc);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret < 0) {
+		dev_err(sd->dev, "serdes initialization failed %d\n", ret);
+		goto done;
+	}
+
+	ret = kserdes_lanes_enable(sc);
+	if (ret < 0) {
+		dev_err(sd->dev, "serdes lanes enable failed: %d\n", ret);
+		goto done;
+	}
+
+	dev_dbg(sd->dev, "serdes config done lanes(mask) 0x%x\n", ret);
+
+done:
+	return ret;
+}
+
+static int kserdes_of_parse_lane(struct device *dev,
+				 struct device_node *np,
+				 struct kserdes_config *sc)
+{
+	struct kserdes_lane_config *lc;
+	struct kserdes_equalizer *eq;
+	struct kserdes_tx_coeff *tc;
+	int lane_num, ret;
+
+	ret = of_property_read_u32(np, "reg", &lane_num);
+	if (ret) {
+		dev_err(dev, "Failed to parse reg\n");
+		return -EINVAL;
+	}
+
+	if (lane_num >= sc->lanes) {
+		dev_err(dev, "Invalid lane number %u\n", lane_num);
+		return -EINVAL;
+	}
+
+	lc = &sc->lane[lane_num];
+	lc->enable = true;
+	dev_dbg(dev, "lane %d enabled\n", lane_num);
+
+	if (of_property_read_u32(np, "control-rate", &lc->ctrl_rate)) {
+		dev_info(dev, "use default lane control-rate: %u\n",
+			 lc->ctrl_rate);
+	}
+	dev_dbg(dev, "lane control-rate: %d\n", lc->ctrl_rate);
+
+	if (of_find_property(np, "loopback", NULL))
+		lc->loopback = true;
+	else
+		lc->loopback = false;
+
+	dev_dbg(dev, "lane loopback: %d\n", lc->loopback);
+
+	eq = &lc->rx_start;
+	if (of_property_read_u32_array(np, "rx-start", &eq->att, 2)) {
+		dev_info(dev, "use default lane rx-start 0 0\n");
+		eq->att = 0;
+		eq->boost = 0;
+	}
+	dev_dbg(dev, "lane rx-start: %d %d\n", eq->att, eq->boost);
+
+	eq = &lc->rx_force;
+	if (of_property_read_u32_array(np, "rx-force", &eq->att, 2)) {
+		dev_info(dev, "use default lane rx-force 0 0\n");
+		eq->att = 0;
+		eq->boost = 0;
+	}
+	dev_dbg(dev, "lane rx-force: %d %d\n", eq->att, eq->boost);
+
+	tc = &lc->tx_coeff;
+	if (of_property_read_u32_array(np, "tx-coeff", &tc->c1, 5)) {
+		dev_info(dev, "use default tx-coeff 0\n");
+		tc->c1 = 0;
+	}
+	dev_dbg(dev, "tx-coeff: %d %d %d %d %d\n",
+		tc->c1, tc->c2, tc->cm, tc->att, tc->vreg);
+
+	return 0;
+}
+
+static void kserdes_set_sgmii_defaults(struct kserdes_config *sc)
+{
+	int i;
+
+	sc->link_rate		= KSERDES_LINK_RATE_1P25G;
+	sc->lanes		= 4;
+	sc->rx_force_enable	= false;
+
+	for (i = 0; i < sc->lanes; i++) {
+		memset(&sc->lane[i], 0, sizeof(sc->lane[i]));
+		sc->lane[i].ctrl_rate = KSERDES_QUARTER_RATE;
+	}
+}
+
+static void kserdes_set_xge_defaults(struct kserdes_config *sc)
+{
+	int i;
+
+	sc->link_rate		= KSERDES_LINK_RATE_10P3125G;
+	sc->lanes		= 2;
+	sc->rx_force_enable	= false;
+
+	for (i = 0; i < sc->lanes; i++) {
+		memset(&sc->lane[i], 0, sizeof(sc->lane[i]));
+		sc->lane[i].ctrl_rate = KSERDES_FULL_RATE;
+	}
+}
+
+static void kserdes_set_pcie_defaults(struct kserdes_config *sc)
+{
+	int i;
+
+	sc->link_rate		= KSERDES_LINK_RATE_5G;
+	sc->lanes		= 2;
+	sc->rx_force_enable	= false;
+
+	for (i = 0; i < sc->lanes; i++)
+		memset(&sc->lane[i], 0, sizeof(sc->lane[i]));
+}
+
+static void kserdes_set_defaults(struct kserdes_config *sc,
+				 enum KSERDES_PHY_TYPE phy_type)
+{
+	switch (phy_type) {
+	case KSERDES_PHY_SGMII:
+		kserdes_set_sgmii_defaults(sc);
+		break;
+	case KSERDES_PHY_XGE:
+		kserdes_set_xge_defaults(sc);
+		break;
+	case KSERDES_PHY_PCIE:
+		kserdes_set_pcie_defaults(sc);
+		break;
+	default:
+		break;
+	}
+}
+
+static int kserdes_of_parse(struct kserdes_dev *sd,
+			    struct device_node *np)
+{
+	struct kserdes_config *sc = &sd->sc;
+	struct device_node *lanes_np, *child;
+	struct device *dev = sd->dev;
+	struct resource res;
+	void __iomem *regs;
+	int ret;
+
+	ret = of_address_to_resource(np, SERDES_REG_INDEX, &res);
+	if (ret) {
+		dev_err(dev, "Can't xlate serdes reg addr of node(%s)\n",
+			np->name);
+		return ret;
+	}
+
+	regs = devm_ioremap_resource(dev, &res);
+	if (IS_ERR(regs)) {
+		dev_err(dev, "Failed to map serdes register base\n");
+		return PTR_ERR(regs);
+	}
+	sc->regs = regs;
+
+	if (of_device_is_compatible(np, "ti,keystone-serdes-gbe")) {
+		sc->phy_type = KSERDES_PHY_SGMII;
+	} else if (of_device_is_compatible(np, "ti,keystone-serdes-xgbe")) {
+		sc->phy_type = KSERDES_PHY_XGE;
+	} else if (of_device_is_compatible(np, "ti,keystone-serdes-pcie")) {
+		sc->phy_type = KSERDES_PHY_PCIE;
+	} else {
+		dev_err(dev, "unknown phy type\n");
+		return -EINVAL;
+	}
+
+	sc->dev = dev;
+
+	/* Set the defaults base on phy type */
+	kserdes_set_defaults(sc, sc->phy_type);
+
+	sc->peripheral_regmap =
+		syscon_regmap_lookup_by_phandle(np, "syscon-peripheral");
+	if (!sc->peripheral_regmap && IS_ERR(sc->peripheral_regmap)) {
+		dev_err(sc->dev,
+			"failed to get syscon-peripheral regmap\n");
+		return PTR_ERR(sc->peripheral_regmap);
+	}
+
+	sc->pcsr_regmap = syscon_regmap_lookup_by_phandle(np, "syscon-link");
+	if (!sc->pcsr_regmap && IS_ERR(sc->pcsr_regmap)) {
+		dev_err(sc->dev,
+			"failed to get syscon-link regmap\n");
+		return PTR_ERR(sc->pcsr_regmap);
+	}
+
+	if (of_property_read_u32(np, "link-rate-kbps", &sc->link_rate)) {
+		dev_info(dev, "use default link-rate-kbps: %u\n",
+			 sc->link_rate);
+	}
+
+	if (of_property_read_u32(np, "num-lanes", &sc->lanes))
+		dev_info(dev, "use default num-lanes %d\n", sc->lanes);
+
+	if (sc->lanes > KSERDES_MAX_LANES) {
+		sc->lanes = KSERDES_MAX_LANES;
+		dev_info(dev, "use max allowed lanes %d\n", sc->lanes);
+	}
+
+	if (of_property_read_bool(np, "rx-force-enable"))
+		sc->rx_force_enable = true;
+	else
+		sc->rx_force_enable = false;
+
+	lanes_np = of_get_child_by_name(np, "lanes");
+	if (lanes_np) {
+		for_each_available_child_of_node(lanes_np, child) {
+			ret = kserdes_of_parse_lane(dev, child, sc);
+			if (ret) {
+				of_node_put(child);
+				of_node_put(lanes_np);
+				return ret;
+			}
+			of_node_put(child);
+		}
+		of_node_put(lanes_np);
+	}
+
+	return 0;
+}
+
+static struct phy_ops kserdes_ops = {
+	.init		= kserdes_init,
+	.owner		= THIS_MODULE,
+};
+
+static int kserdes_probe(struct platform_device *pdev)
+{
+	struct phy_provider *phy_provider;
+	struct kserdes_dev *sd;
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	sd = devm_kzalloc(dev, sizeof(*sd), GFP_KERNEL);
+	if (!sd)
+		return -ENOMEM;
+
+	sd->dev = dev;
+
+	ret = kserdes_of_parse(sd, np);
+	if (ret)
+		return ret;
+
+	dev_set_drvdata(dev, sd);
+	sd->phy = devm_phy_create(dev, NULL, &kserdes_ops);
+	if (IS_ERR(sd->phy))
+		return PTR_ERR(sd->phy);
+
+	phy_set_drvdata(sd->phy, sd);
+	phy_provider = devm_of_phy_provider_register(sd->dev,
+						     of_phy_simple_xlate);
+
+	if (IS_ERR(phy_provider))
+		return PTR_ERR_OR_ZERO(phy_provider);
+
+	dev_vdbg(&pdev->dev, "probed");
+	return 0;
+}
+
+static const struct of_device_id kserdes_of_match[] = {
+	{ .compatible = "ti,keystone-serdes-gbe" },
+	{ .compatible = "ti,keystone-serdes-pcie" },
+	{ .compatible = "ti,keystone-serdes-xgbe" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, kserdes_of_match);
+
+static struct platform_driver kserdes_driver = {
+	.probe	= kserdes_probe,
+	.driver = {
+		.of_match_table	= kserdes_of_match,
+		.name  = "ti,keystone-serdes",
+	}
+};
+
+static int __init keystone_serdes_phy_init(void)
+{
+	return platform_driver_register(&kserdes_driver);
+}
+module_init(keystone_serdes_phy_init);
+
+static void __exit keystone_serdes_phy_exit(void)
+{
+	platform_driver_unregister(&kserdes_driver);
+}
+module_exit(keystone_serdes_phy_exit);
+
+MODULE_AUTHOR("WingMan Kwok <w-kwok2@ti.com>");
+MODULE_DESCRIPTION("TI Keystone SerDes driver");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v1 2/2] PCI: keystone: update to use generic keystone serdes driver
  2015-10-15 14:25 ` WingMan Kwok
  (?)
@ 2015-10-15 14:25   ` WingMan Kwok
  -1 siblings, 0 replies; 63+ messages in thread
From: WingMan Kwok @ 2015-10-15 14:25 UTC (permalink / raw
  To: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, kishon,
	rogerq, m-karicheri2, bhelgaas, ssantosh, linux, devicetree,
	linux-kernel, linux-pci, linux-arm-kernel
  Cc: WingMan Kwok

This patch updates the Keystone PCI driver to use the
generic Keystone serdes driver for serdes initialization
and configuration.  The generic serdes driver supports
peripherals on Keystone platforms that require serdes.

v1:
	- no change.

Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
---
 drivers/pci/host/pci-keystone.c |   54 ++++++++++++++++++++++++++++++++-------
 drivers/pci/host/pci-keystone.h |    2 ++
 2 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
index 0aa81bd..b4de05b 100644
--- a/drivers/pci/host/pci-keystone.c
+++ b/drivers/pci/host/pci-keystone.c
@@ -335,6 +335,7 @@ static int __exit ks_pcie_remove(struct platform_device *pdev)
 {
 	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
 
+	phy_exit(ks_pcie->serdes_phy);
 	clk_disable_unprepare(ks_pcie->clk);
 
 	return 0;
@@ -342,6 +343,8 @@ static int __exit ks_pcie_remove(struct platform_device *pdev)
 
 static int __init ks_pcie_probe(struct platform_device *pdev)
 {
+	struct device_node *node = pdev->dev.of_node;
+	struct device_node *serdeses_np, *child;
 	struct device *dev = &pdev->dev;
 	struct keystone_pcie *ks_pcie;
 	struct pcie_port *pp;
@@ -349,6 +352,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 	void __iomem *reg_p;
 	struct phy *phy;
 	int ret = 0;
+	u32 phy_num;
 
 	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
 				GFP_KERNEL);
@@ -357,14 +361,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 
 	pp = &ks_pcie->pp;
 
-	/* initialize SerDes Phy if present */
-	phy = devm_phy_get(dev, "pcie-phy");
-	if (!IS_ERR_OR_NULL(phy)) {
-		ret = phy_init(phy);
-		if (ret < 0)
-			return ret;
-	}
-
 	/* index 2 is to read PCI DEVICE_ID */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
 	reg_p = devm_ioremap_resource(dev, res);
@@ -385,6 +381,46 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	serdeses_np = of_get_child_by_name(node, "serdeses");
+	if (serdeses_np) {
+		for_each_available_child_of_node(serdeses_np, child) {
+			ret = of_property_read_u32(child, "reg", &phy_num);
+			if (ret) {
+				dev_err(dev, "Failed to parse device tree\n");
+				of_node_put(child);
+				of_node_put(serdeses_np);
+				goto fail_clk;
+			}
+
+			if (phy_num >= MAX_NUM_PCI_SERDES) {
+				dev_err(dev, "Invalid phy number: %u\n",
+					phy_num);
+				of_node_put(child);
+				of_node_put(serdeses_np);
+				ret = -EINVAL;
+				goto fail_clk;
+			}
+
+			phy = devm_of_phy_get(dev, child, NULL);
+			of_node_put(child);
+			ks_pcie->serdes_phy = phy;
+			if (IS_ERR(phy)) {
+				dev_err(dev, "No %s serdes driver found: %ld\n",
+					node->name, PTR_ERR(phy));
+				of_node_put(serdeses_np);
+				ret = PTR_ERR(phy);
+				goto fail_clk;
+			}
+
+			ret = phy_init(phy);
+			if (ret < 0) {
+				of_node_put(serdeses_np);
+				goto fail_clk;
+			}
+		}
+		of_node_put(serdeses_np);
+	}
+
 	ret = ks_add_pcie_port(ks_pcie, pdev);
 	if (ret < 0)
 		goto fail_clk;
@@ -392,7 +428,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 	return 0;
 fail_clk:
 	clk_disable_unprepare(ks_pcie->clk);
-
+	phy_exit(ks_pcie->serdes_phy);
 	return ret;
 }
 
diff --git a/drivers/pci/host/pci-keystone.h b/drivers/pci/host/pci-keystone.h
index 478d932..21662ba 100644
--- a/drivers/pci/host/pci-keystone.h
+++ b/drivers/pci/host/pci-keystone.h
@@ -15,6 +15,7 @@
 #define MAX_LEGACY_IRQS			4
 #define MAX_MSI_HOST_IRQS		8
 #define MAX_LEGACY_HOST_IRQS		4
+#define MAX_NUM_PCI_SERDES		1
 
 struct keystone_pcie {
 	struct	clk		*clk;
@@ -33,6 +34,7 @@ struct keystone_pcie {
 	/* Application register space */
 	void __iomem		*va_app_base;
 	struct resource		app;
+	struct phy		*serdes_phy;
 };
 
 /* Keystone DW specific MSI controller APIs/definitions */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v1 2/2] PCI: keystone: update to use generic keystone serdes driver
@ 2015-10-15 14:25   ` WingMan Kwok
  0 siblings, 0 replies; 63+ messages in thread
From: WingMan Kwok @ 2015-10-15 14:25 UTC (permalink / raw
  To: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, kishon,
	rogerq, m-karicheri2, bhelgaas, ssantosh, linux, devicetree,
	linux-kernel, linux-pci, linux-arm-kernel
  Cc: WingMan Kwok

This patch updates the Keystone PCI driver to use the
generic Keystone serdes driver for serdes initialization
and configuration.  The generic serdes driver supports
peripherals on Keystone platforms that require serdes.

v1:
	- no change.

Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
---
 drivers/pci/host/pci-keystone.c |   54 ++++++++++++++++++++++++++++++++-------
 drivers/pci/host/pci-keystone.h |    2 ++
 2 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
index 0aa81bd..b4de05b 100644
--- a/drivers/pci/host/pci-keystone.c
+++ b/drivers/pci/host/pci-keystone.c
@@ -335,6 +335,7 @@ static int __exit ks_pcie_remove(struct platform_device *pdev)
 {
 	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
 
+	phy_exit(ks_pcie->serdes_phy);
 	clk_disable_unprepare(ks_pcie->clk);
 
 	return 0;
@@ -342,6 +343,8 @@ static int __exit ks_pcie_remove(struct platform_device *pdev)
 
 static int __init ks_pcie_probe(struct platform_device *pdev)
 {
+	struct device_node *node = pdev->dev.of_node;
+	struct device_node *serdeses_np, *child;
 	struct device *dev = &pdev->dev;
 	struct keystone_pcie *ks_pcie;
 	struct pcie_port *pp;
@@ -349,6 +352,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 	void __iomem *reg_p;
 	struct phy *phy;
 	int ret = 0;
+	u32 phy_num;
 
 	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
 				GFP_KERNEL);
@@ -357,14 +361,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 
 	pp = &ks_pcie->pp;
 
-	/* initialize SerDes Phy if present */
-	phy = devm_phy_get(dev, "pcie-phy");
-	if (!IS_ERR_OR_NULL(phy)) {
-		ret = phy_init(phy);
-		if (ret < 0)
-			return ret;
-	}
-
 	/* index 2 is to read PCI DEVICE_ID */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
 	reg_p = devm_ioremap_resource(dev, res);
@@ -385,6 +381,46 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	serdeses_np = of_get_child_by_name(node, "serdeses");
+	if (serdeses_np) {
+		for_each_available_child_of_node(serdeses_np, child) {
+			ret = of_property_read_u32(child, "reg", &phy_num);
+			if (ret) {
+				dev_err(dev, "Failed to parse device tree\n");
+				of_node_put(child);
+				of_node_put(serdeses_np);
+				goto fail_clk;
+			}
+
+			if (phy_num >= MAX_NUM_PCI_SERDES) {
+				dev_err(dev, "Invalid phy number: %u\n",
+					phy_num);
+				of_node_put(child);
+				of_node_put(serdeses_np);
+				ret = -EINVAL;
+				goto fail_clk;
+			}
+
+			phy = devm_of_phy_get(dev, child, NULL);
+			of_node_put(child);
+			ks_pcie->serdes_phy = phy;
+			if (IS_ERR(phy)) {
+				dev_err(dev, "No %s serdes driver found: %ld\n",
+					node->name, PTR_ERR(phy));
+				of_node_put(serdeses_np);
+				ret = PTR_ERR(phy);
+				goto fail_clk;
+			}
+
+			ret = phy_init(phy);
+			if (ret < 0) {
+				of_node_put(serdeses_np);
+				goto fail_clk;
+			}
+		}
+		of_node_put(serdeses_np);
+	}
+
 	ret = ks_add_pcie_port(ks_pcie, pdev);
 	if (ret < 0)
 		goto fail_clk;
@@ -392,7 +428,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 	return 0;
 fail_clk:
 	clk_disable_unprepare(ks_pcie->clk);
-
+	phy_exit(ks_pcie->serdes_phy);
 	return ret;
 }
 
diff --git a/drivers/pci/host/pci-keystone.h b/drivers/pci/host/pci-keystone.h
index 478d932..21662ba 100644
--- a/drivers/pci/host/pci-keystone.h
+++ b/drivers/pci/host/pci-keystone.h
@@ -15,6 +15,7 @@
 #define MAX_LEGACY_IRQS			4
 #define MAX_MSI_HOST_IRQS		8
 #define MAX_LEGACY_HOST_IRQS		4
+#define MAX_NUM_PCI_SERDES		1
 
 struct keystone_pcie {
 	struct	clk		*clk;
@@ -33,6 +34,7 @@ struct keystone_pcie {
 	/* Application register space */
 	void __iomem		*va_app_base;
 	struct resource		app;
+	struct phy		*serdes_phy;
 };
 
 /* Keystone DW specific MSI controller APIs/definitions */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* [PATCH v1 2/2] PCI: keystone: update to use generic keystone serdes driver
@ 2015-10-15 14:25   ` WingMan Kwok
  0 siblings, 0 replies; 63+ messages in thread
From: WingMan Kwok @ 2015-10-15 14:25 UTC (permalink / raw
  To: linux-arm-kernel

This patch updates the Keystone PCI driver to use the
generic Keystone serdes driver for serdes initialization
and configuration.  The generic serdes driver supports
peripherals on Keystone platforms that require serdes.

v1:
	- no change.

Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
---
 drivers/pci/host/pci-keystone.c |   54 ++++++++++++++++++++++++++++++++-------
 drivers/pci/host/pci-keystone.h |    2 ++
 2 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
index 0aa81bd..b4de05b 100644
--- a/drivers/pci/host/pci-keystone.c
+++ b/drivers/pci/host/pci-keystone.c
@@ -335,6 +335,7 @@ static int __exit ks_pcie_remove(struct platform_device *pdev)
 {
 	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
 
+	phy_exit(ks_pcie->serdes_phy);
 	clk_disable_unprepare(ks_pcie->clk);
 
 	return 0;
@@ -342,6 +343,8 @@ static int __exit ks_pcie_remove(struct platform_device *pdev)
 
 static int __init ks_pcie_probe(struct platform_device *pdev)
 {
+	struct device_node *node = pdev->dev.of_node;
+	struct device_node *serdeses_np, *child;
 	struct device *dev = &pdev->dev;
 	struct keystone_pcie *ks_pcie;
 	struct pcie_port *pp;
@@ -349,6 +352,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 	void __iomem *reg_p;
 	struct phy *phy;
 	int ret = 0;
+	u32 phy_num;
 
 	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
 				GFP_KERNEL);
@@ -357,14 +361,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 
 	pp = &ks_pcie->pp;
 
-	/* initialize SerDes Phy if present */
-	phy = devm_phy_get(dev, "pcie-phy");
-	if (!IS_ERR_OR_NULL(phy)) {
-		ret = phy_init(phy);
-		if (ret < 0)
-			return ret;
-	}
-
 	/* index 2 is to read PCI DEVICE_ID */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
 	reg_p = devm_ioremap_resource(dev, res);
@@ -385,6 +381,46 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	serdeses_np = of_get_child_by_name(node, "serdeses");
+	if (serdeses_np) {
+		for_each_available_child_of_node(serdeses_np, child) {
+			ret = of_property_read_u32(child, "reg", &phy_num);
+			if (ret) {
+				dev_err(dev, "Failed to parse device tree\n");
+				of_node_put(child);
+				of_node_put(serdeses_np);
+				goto fail_clk;
+			}
+
+			if (phy_num >= MAX_NUM_PCI_SERDES) {
+				dev_err(dev, "Invalid phy number: %u\n",
+					phy_num);
+				of_node_put(child);
+				of_node_put(serdeses_np);
+				ret = -EINVAL;
+				goto fail_clk;
+			}
+
+			phy = devm_of_phy_get(dev, child, NULL);
+			of_node_put(child);
+			ks_pcie->serdes_phy = phy;
+			if (IS_ERR(phy)) {
+				dev_err(dev, "No %s serdes driver found: %ld\n",
+					node->name, PTR_ERR(phy));
+				of_node_put(serdeses_np);
+				ret = PTR_ERR(phy);
+				goto fail_clk;
+			}
+
+			ret = phy_init(phy);
+			if (ret < 0) {
+				of_node_put(serdeses_np);
+				goto fail_clk;
+			}
+		}
+		of_node_put(serdeses_np);
+	}
+
 	ret = ks_add_pcie_port(ks_pcie, pdev);
 	if (ret < 0)
 		goto fail_clk;
@@ -392,7 +428,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
 	return 0;
 fail_clk:
 	clk_disable_unprepare(ks_pcie->clk);
-
+	phy_exit(ks_pcie->serdes_phy);
 	return ret;
 }
 
diff --git a/drivers/pci/host/pci-keystone.h b/drivers/pci/host/pci-keystone.h
index 478d932..21662ba 100644
--- a/drivers/pci/host/pci-keystone.h
+++ b/drivers/pci/host/pci-keystone.h
@@ -15,6 +15,7 @@
 #define MAX_LEGACY_IRQS			4
 #define MAX_MSI_HOST_IRQS		8
 #define MAX_LEGACY_HOST_IRQS		4
+#define MAX_NUM_PCI_SERDES		1
 
 struct keystone_pcie {
 	struct	clk		*clk;
@@ -33,6 +34,7 @@ struct keystone_pcie {
 	/* Application register space */
 	void __iomem		*va_app_base;
 	struct resource		app;
+	struct phy		*serdes_phy;
 };
 
 /* Keystone DW specific MSI controller APIs/definitions */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-15 14:25   ` WingMan Kwok
@ 2015-10-15 14:51     ` Arnd Bergmann
  -1 siblings, 0 replies; 63+ messages in thread
From: Arnd Bergmann @ 2015-10-15 14:51 UTC (permalink / raw
  To: linux-arm-kernel
  Cc: WingMan Kwok, robh+dt, pawel.moll, mark.rutland, ijc+devicetree,
	galak, kishon, rogerq, m-karicheri2, bhelgaas, ssantosh, linux,
	devicetree, linux-kernel, linux-pci

On Thursday 15 October 2015 10:25:44 WingMan Kwok wrote:
> On TI's Keystone platforms, several peripherals such as the
> gbe ethernet switch, 10gbe ethernet switch and PCIe controller
> require the use of a SerDes for converting SoC parallel data into
> serialized data that can be output over a high-speed electrical
> interface, and also converting high-speed serial input data
> into parallel data that can be processed by the SoC.  The
> SerDeses used by those peripherals, though they may be different,
> are largely similar in functionality and setup.
> 
> This patch provides a SerDes phy driver implementation that can be
> used by the above mentioned peripheral drivers to configure their
> respective SerDeses.
> 
> v1:
> 	- see cover letter for review comments addressed.
> 
> Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
> ---
>  Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
>  drivers/phy/Kconfig                              |    8 +
>  drivers/phy/Makefile                             |    1 +
>  drivers/phy/phy-keystone-serdes.c                | 2373 ++++++++++++++++++++++
>  4 files changed, 2660 insertions(+)
>  create mode 100644 drivers/phy/phy-keystone-serdes.c

This is quite a bit of code. Are you very sure that this PHY is
not used on any other SoC family, and that it is not licensed
from a third party? I would hate to see multiple copies of
this getting merged into the kernel over time, so thename should
be chosen carefully to let the next person know when they have
related hardware.

> +
> +gbe_serdes0: gbe_serdes@232a000 {


make that phy@232a000, the name should be one of the usual identifiers,
not specific to the instance.

> +config PHY_TI_KEYSTONE_SERDES
> +	tristate "TI Keystone SerDes PHY support"
> +	depends on OF && ARCH_KEYSTONE
> +	select GENERIC_PHY
> +	help
> +	  This option enables support for TI Keystone SerDes PHY found
> +	  in peripherals GBE, 10GBE and PCIe.
> +

(ARCH_KEYSTONE || COMPILE_TEST) ?

> + * Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in the
> + * documentation and/or other materials provided with the
> + * distribution.

The current code does not do this when compiled, which might be a
problem for distributors. Can you clarify the license?

> +#define reg_rmw(addr, value, mask) \
> +	__raw_writel(((__raw_readl(addr) & (~(mask))) | \
> +			(value & (mask))), (addr))

not endian safe, and potentially racy.

> +static inline void _kserdes_reset_cdr(void __iomem *sregs, int lane)
> +{
> +	/* toggle signal detect */
> +	_kserdes_force_signal_detect_low(sregs, lane);
> +	mdelay(1);
> +	_kserdes_force_signal_detect_high(sregs, lane);
> +}

Can you change the code so you can use msleep(1) here?

> +
> +	do {
> +		mdelay(10);
> +		memset(lane_down, 0, sizeof(lane_down));
> +
> +		link_up = _kserdes_check_link_status(dev, sregs,
> +						     pcsr_regmap, lanes,
> +						     lanes_enable,
> +						     current_state, lane_down);
> +
> +		/* if we did not get link up then wait 100ms
> +		 * before calling it again
> +		 */
> +		if (link_up)
> +			break;
> +
> +		for (i = 0; i < lanes; i++) {
> +			if ((lanes_enable & (1 << i)) && lane_down[i])
> +				dev_dbg(dev,
> +					"XGE: detected lane down on lane %d\n",
> +					i);
> +		}
> +
> +		if (++retries > 100)
> +			return -ETIMEDOUT;
> +
> +	} while (!link_up);

an more importantly here. Blocking the CPU for over one second is not good.

Any use of mdelay() should have a comment explaining why you cannot use
msleep() in that instance.

> +
> +static int __init keystone_serdes_phy_init(void)
> +{
> +	return platform_driver_register(&kserdes_driver);
> +}
> +module_init(keystone_serdes_phy_init);
> +
> +static void __exit keystone_serdes_phy_exit(void)
> +{
> +	platform_driver_unregister(&kserdes_driver);
> +}
> +module_exit(keystone_serdes_phy_exit);

module_platform_driver()

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 14:51     ` Arnd Bergmann
  0 siblings, 0 replies; 63+ messages in thread
From: Arnd Bergmann @ 2015-10-15 14:51 UTC (permalink / raw
  To: linux-arm-kernel

On Thursday 15 October 2015 10:25:44 WingMan Kwok wrote:
> On TI's Keystone platforms, several peripherals such as the
> gbe ethernet switch, 10gbe ethernet switch and PCIe controller
> require the use of a SerDes for converting SoC parallel data into
> serialized data that can be output over a high-speed electrical
> interface, and also converting high-speed serial input data
> into parallel data that can be processed by the SoC.  The
> SerDeses used by those peripherals, though they may be different,
> are largely similar in functionality and setup.
> 
> This patch provides a SerDes phy driver implementation that can be
> used by the above mentioned peripheral drivers to configure their
> respective SerDeses.
> 
> v1:
> 	- see cover letter for review comments addressed.
> 
> Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
> ---
>  Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
>  drivers/phy/Kconfig                              |    8 +
>  drivers/phy/Makefile                             |    1 +
>  drivers/phy/phy-keystone-serdes.c                | 2373 ++++++++++++++++++++++
>  4 files changed, 2660 insertions(+)
>  create mode 100644 drivers/phy/phy-keystone-serdes.c

This is quite a bit of code. Are you very sure that this PHY is
not used on any other SoC family, and that it is not licensed
from a third party? I would hate to see multiple copies of
this getting merged into the kernel over time, so thename should
be chosen carefully to let the next person know when they have
related hardware.

> +
> +gbe_serdes0: gbe_serdes at 232a000 {


make that phy at 232a000, the name should be one of the usual identifiers,
not specific to the instance.

> +config PHY_TI_KEYSTONE_SERDES
> +	tristate "TI Keystone SerDes PHY support"
> +	depends on OF && ARCH_KEYSTONE
> +	select GENERIC_PHY
> +	help
> +	  This option enables support for TI Keystone SerDes PHY found
> +	  in peripherals GBE, 10GBE and PCIe.
> +

(ARCH_KEYSTONE || COMPILE_TEST) ?

> + * Redistributions in binary form must reproduce the above copyright
> + * notice, this list of conditions and the following disclaimer in the
> + * documentation and/or other materials provided with the
> + * distribution.

The current code does not do this when compiled, which might be a
problem for distributors. Can you clarify the license?

> +#define reg_rmw(addr, value, mask) \
> +	__raw_writel(((__raw_readl(addr) & (~(mask))) | \
> +			(value & (mask))), (addr))

not endian safe, and potentially racy.

> +static inline void _kserdes_reset_cdr(void __iomem *sregs, int lane)
> +{
> +	/* toggle signal detect */
> +	_kserdes_force_signal_detect_low(sregs, lane);
> +	mdelay(1);
> +	_kserdes_force_signal_detect_high(sregs, lane);
> +}

Can you change the code so you can use msleep(1) here?

> +
> +	do {
> +		mdelay(10);
> +		memset(lane_down, 0, sizeof(lane_down));
> +
> +		link_up = _kserdes_check_link_status(dev, sregs,
> +						     pcsr_regmap, lanes,
> +						     lanes_enable,
> +						     current_state, lane_down);
> +
> +		/* if we did not get link up then wait 100ms
> +		 * before calling it again
> +		 */
> +		if (link_up)
> +			break;
> +
> +		for (i = 0; i < lanes; i++) {
> +			if ((lanes_enable & (1 << i)) && lane_down[i])
> +				dev_dbg(dev,
> +					"XGE: detected lane down on lane %d\n",
> +					i);
> +		}
> +
> +		if (++retries > 100)
> +			return -ETIMEDOUT;
> +
> +	} while (!link_up);

an more importantly here. Blocking the CPU for over one second is not good.

Any use of mdelay() should have a comment explaining why you cannot use
msleep() in that instance.

> +
> +static int __init keystone_serdes_phy_init(void)
> +{
> +	return platform_driver_register(&kserdes_driver);
> +}
> +module_init(keystone_serdes_phy_init);
> +
> +static void __exit keystone_serdes_phy_exit(void)
> +{
> +	platform_driver_unregister(&kserdes_driver);
> +}
> +module_exit(keystone_serdes_phy_exit);

module_platform_driver()

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-15 14:51     ` Arnd Bergmann
  (?)
@ 2015-10-15 16:01       ` Murali Karicheri
  -1 siblings, 0 replies; 63+ messages in thread
From: Murali Karicheri @ 2015-10-15 16:01 UTC (permalink / raw
  To: Arnd Bergmann, linux-arm-kernel
  Cc: WingMan Kwok, robh+dt, pawel.moll, mark.rutland, ijc+devicetree,
	galak, kishon, rogerq, bhelgaas, ssantosh, linux, devicetree,
	linux-kernel, linux-pci

On 10/15/2015 10:51 AM, Arnd Bergmann wrote:
> On Thursday 15 October 2015 10:25:44 WingMan Kwok wrote:
>> On TI's Keystone platforms, several peripherals such as the
>> gbe ethernet switch, 10gbe ethernet switch and PCIe controller
>> require the use of a SerDes for converting SoC parallel data into
>> serialized data that can be output over a high-speed electrical
>> interface, and also converting high-speed serial input data
>> into parallel data that can be processed by the SoC.  The
>> SerDeses used by those peripherals, though they may be different,
>> are largely similar in functionality and setup.
>>
>> This patch provides a SerDes phy driver implementation that can be
>> used by the above mentioned peripheral drivers to configure their
>> respective SerDeses.
>>
>> v1:

--------cut-------------------------------------------------------------

>> + * Redistributions in binary form must reproduce the above copyright
>> + * notice, this list of conditions and the following disclaimer in the
>> + * documentation and/or other materials provided with the
>> + * distribution.
>
> The current code does not do this when compiled, which might be a
> problem for distributors. Can you clarify the license?
>
Arnd,

Can you elaborate on this? I did a grep on the string "Redistributions 
in binary form must reproduce the above copyright" and I could find 
several instance of this. So I am not sure what you mean by "The current 
code does not do this when compiled".

Thanks
-- 
Murali Karicheri
Linux Kernel, Keystone

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 16:01       ` Murali Karicheri
  0 siblings, 0 replies; 63+ messages in thread
From: Murali Karicheri @ 2015-10-15 16:01 UTC (permalink / raw
  To: Arnd Bergmann, linux-arm-kernel
  Cc: WingMan Kwok, robh+dt, pawel.moll, mark.rutland, ijc+devicetree,
	galak, kishon, rogerq, bhelgaas, ssantosh, linux, devicetree,
	linux-kernel, linux-pci

On 10/15/2015 10:51 AM, Arnd Bergmann wrote:
> On Thursday 15 October 2015 10:25:44 WingMan Kwok wrote:
>> On TI's Keystone platforms, several peripherals such as the
>> gbe ethernet switch, 10gbe ethernet switch and PCIe controller
>> require the use of a SerDes for converting SoC parallel data into
>> serialized data that can be output over a high-speed electrical
>> interface, and also converting high-speed serial input data
>> into parallel data that can be processed by the SoC.  The
>> SerDeses used by those peripherals, though they may be different,
>> are largely similar in functionality and setup.
>>
>> This patch provides a SerDes phy driver implementation that can be
>> used by the above mentioned peripheral drivers to configure their
>> respective SerDeses.
>>
>> v1:

--------cut-------------------------------------------------------------

>> + * Redistributions in binary form must reproduce the above copyright
>> + * notice, this list of conditions and the following disclaimer in the
>> + * documentation and/or other materials provided with the
>> + * distribution.
>
> The current code does not do this when compiled, which might be a
> problem for distributors. Can you clarify the license?
>
Arnd,

Can you elaborate on this? I did a grep on the string "Redistributions 
in binary form must reproduce the above copyright" and I could find 
several instance of this. So I am not sure what you mean by "The current 
code does not do this when compiled".

Thanks
-- 
Murali Karicheri
Linux Kernel, Keystone

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 16:01       ` Murali Karicheri
  0 siblings, 0 replies; 63+ messages in thread
From: Murali Karicheri @ 2015-10-15 16:01 UTC (permalink / raw
  To: linux-arm-kernel

On 10/15/2015 10:51 AM, Arnd Bergmann wrote:
> On Thursday 15 October 2015 10:25:44 WingMan Kwok wrote:
>> On TI's Keystone platforms, several peripherals such as the
>> gbe ethernet switch, 10gbe ethernet switch and PCIe controller
>> require the use of a SerDes for converting SoC parallel data into
>> serialized data that can be output over a high-speed electrical
>> interface, and also converting high-speed serial input data
>> into parallel data that can be processed by the SoC.  The
>> SerDeses used by those peripherals, though they may be different,
>> are largely similar in functionality and setup.
>>
>> This patch provides a SerDes phy driver implementation that can be
>> used by the above mentioned peripheral drivers to configure their
>> respective SerDeses.
>>
>> v1:

--------cut-------------------------------------------------------------

>> + * Redistributions in binary form must reproduce the above copyright
>> + * notice, this list of conditions and the following disclaimer in the
>> + * documentation and/or other materials provided with the
>> + * distribution.
>
> The current code does not do this when compiled, which might be a
> problem for distributors. Can you clarify the license?
>
Arnd,

Can you elaborate on this? I did a grep on the string "Redistributions 
in binary form must reproduce the above copyright" and I could find 
several instance of this. So I am not sure what you mean by "The current 
code does not do this when compiled".

Thanks
-- 
Murali Karicheri
Linux Kernel, Keystone

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-15 14:25   ` WingMan Kwok
@ 2015-10-15 16:14     ` Rob Herring
  -1 siblings, 0 replies; 63+ messages in thread
From: Rob Herring @ 2015-10-15 16:14 UTC (permalink / raw
  To: WingMan Kwok
  Cc: Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Kishon Vijay Abraham I, Roger Quadros, Murali Karicheri,
	Bjorn Helgaas, Santosh Shilimkar, Russell King - ARM Linux,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org

On Thu, Oct 15, 2015 at 9:25 AM, WingMan Kwok <w-kwok2@ti.com> wrote:
> On TI's Keystone platforms, several peripherals such as the
> gbe ethernet switch, 10gbe ethernet switch and PCIe controller
> require the use of a SerDes for converting SoC parallel data into
> serialized data that can be output over a high-speed electrical
> interface, and also converting high-speed serial input data
> into parallel data that can be processed by the SoC.  The
> SerDeses used by those peripherals, though they may be different,
> are largely similar in functionality and setup.
>
> This patch provides a SerDes phy driver implementation that can be
> used by the above mentioned peripheral drivers to configure their
> respective SerDeses.
>
> v1:
>         - see cover letter for review comments addressed.
>
> Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
> ---
>  Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
>  drivers/phy/Kconfig                              |    8 +
>  drivers/phy/Makefile                             |    1 +
>  drivers/phy/phy-keystone-serdes.c                | 2373 ++++++++++++++++++++++
>  4 files changed, 2660 insertions(+)
>  create mode 100644 drivers/phy/phy-keystone-serdes.c
>
> diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt
> index 9cf9446..4dca271 100644
> --- a/Documentation/devicetree/bindings/phy/ti-phy.txt
> +++ b/Documentation/devicetree/bindings/phy/ti-phy.txt
> @@ -115,4 +115,282 @@ sata_phy: phy@4A096000 {
>         clock-names = "sysclk", "refclk";
>         syscon-pllreset = <&scm_conf 0x3fc>;
>         #phy-cells = <0>;
> +
> +TI Keystone SerDes PHY
> +======================
> +
> +Required properties:
> + - compatible: should be one of
> +       * "ti,keystone-serdes-gbe"
> +       * "ti,keystone-serdes-xgbe"
> +       * "ti,keystone-serdes-pcie"

These are different blocks or different modes of the same block? It's
fine if the former. If the latter, then you should have a single
compatible and then have a mode property. Perhaps phy-connection-type
from ePAPR ethernet binding can be extended.


> + - reg:
> +       * base address and length of the SerDes register set
> + - reg-names:
> +       * "serdes"
> +               - name of the reg SerDes register set

reg-names is kind of pointless with only 1.

> + - #phy-cells:
> +       * From the generic phy bindings, must be 0;
> + - num-lanes:
> +       * Number of lanes in SerDes.
> +
> +Optional properties:
> + - syscon-peripheral:
> +       * Handle to the subsystem register region of the peripheral
> +         inside which the SerDes exists.
> + - syscon-link:
> +       * Handle to the Link register region of the peripheral inside
> +         which the SerDes exists.  Example: it is the PCSR register
> +         region in the case of 10gbe.
> + - rx-force-enable:
> +       * Include this property if receiver attenuation and boost are
> +         to be configured with specific values defined in rx-force.
> + - link-rate-kbps:
> +       * SerDes link rate to be configured, in kbps.
> +
> +
> +For gbe and 10gbe SerDes, it is optional to represent each lane as
> +a sub-node, which can be enabled or disabled individually using
> +the "status" property.
> +
> +Required properties (lane sub-node):
> + - reg:
> +       * lane number
> +
> +Optional properties (lane sub-node):
> + - control-rate:
> +       * Lane control rate
> +               0: full rate
> +               1: half rate
> +               2: quarter rate
> + - rx-start:
> +       * Initial lane rx equalizer attenuation and boost configurations.
> +       * Must be array of 2 integers.
> + - rx-force:
> +       * Forced lane rx equalizer attenuation and boost configurations.
> +       * Must be array of 2 integers.
> + - tx-coeff:
> +       * Lane c1, c2, cm, attenuation and regulator output voltage
> +         configurations.
> +       * Must be array of 5 integers.
> + - loopback:
> +       * Include this property to enable loopback at the SerDes
> +         lane level.

This seems overly complicated. Do you really expect these to be
different per lane?

> +
> +Example for Keystone K2E GBE:
> +-----------------------------
> +
> +gbe_serdes0: gbe_serdes@232a000 {
> +       #phy-cells              = <0>;
> +       compatible              = "ti,keystone-serdes-gbe";
> +       reg                     = <0x0232a000 0x2000>;
> +       reg-names               = "serdes";
> +       link-rate-kbps          = <1250000>;
> +       num-lanes               = <4>;
> +       lanes {
> +               #address-cells = <1>;
> +               #size-cells = <0>;
> +               lane@0 {
> +                       /*loopback;*/
> +                       reg             = <0>;
> +                       control-rate    = <2>; /* quart */
> +                       rx-start        = <7 5>;
> +                       rx-force        = <1 1>;
> +                       tx-coeff        = <0 0 0 12 4>;
> +                              /* c1 c2 cm att vreg */
> +               };
> +               lane@1 {
> +                       /*loopback;*/
> +                       reg             = <1>;
> +                       control-rate    = <2>; /* quart */
> +                       rx-start        = <7 5>;
> +                       rx-force        = <1 1>;
> +                       tx-coeff        = <0 0 0 12 4>;
> +                              /* c1 c2 cm att vreg */
> +               };
> +       };
> +};
> +
> +gbe_serdes1: gbe_serdes@2324000 {
> +       #phy-cells              = <0>;
> +       compatible              = "ti,keystone-serdes-gbe";
> +       reg                     = <0x02324000 0x2000>;
> +       reg-names               = "serdes";
> +       link-rate-kbps          = <1250000>;
> +       num-lanes               = <4>;

4 lanes, but only 2 child nodes?

> +       lanes {
> +               #address-cells = <1>;
> +               #size-cells = <0>;
> +               lane@0 {
> +                       /*loopback;*/
> +                       reg             = <0>;
> +                       control-rate    = <2>; /* quart */
> +                       rx-start        = <7 5>;
> +                       rx-force        = <1 1>;
> +                       tx-coeff        = <0 0 0 12 4>;
> +                              /* c1 c2 cm att vreg */
> +               };
> +               lane@1 {
> +                       /*loopback;*/
> +                       reg             = <1>;
> +                       control-rate    = <2>; /* quart */
> +                       rx-start        = <7 5>;
> +                       rx-force        = <1 1>;
> +                       tx-coeff        = <0 0 0 12 4>;
> +                              /* c1 c2 cm att vreg */
> +               };
> +       };
> +};
> +
> +netcp: netcp@24000000 {
> +       ...
> +
> +       netcp-devices {
> +               ...
> +
> +               gbe@200000 { /* ETHSS */
> +                       ...
> +                       serdeses {
> +                               #address-cells = <1>;
> +                               #size-cells = <0>;
> +                               serdes@0 {
> +                                       reg = <0>;
> +                                       phys = <&gbe_serdes0>;
> +                                       status = "ok";
> +                               };
> +                               serdes@1 {
> +                                       reg = <1>;
> +                                       phys = <&gbe_serdes1>;
> +                                       status = "ok";

This is way too complex. Just do:

phys = <&gbe_serdes0, &gbe_serdes1>;

in the gbe node.

Rob

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 16:14     ` Rob Herring
  0 siblings, 0 replies; 63+ messages in thread
From: Rob Herring @ 2015-10-15 16:14 UTC (permalink / raw
  To: linux-arm-kernel

On Thu, Oct 15, 2015 at 9:25 AM, WingMan Kwok <w-kwok2@ti.com> wrote:
> On TI's Keystone platforms, several peripherals such as the
> gbe ethernet switch, 10gbe ethernet switch and PCIe controller
> require the use of a SerDes for converting SoC parallel data into
> serialized data that can be output over a high-speed electrical
> interface, and also converting high-speed serial input data
> into parallel data that can be processed by the SoC.  The
> SerDeses used by those peripherals, though they may be different,
> are largely similar in functionality and setup.
>
> This patch provides a SerDes phy driver implementation that can be
> used by the above mentioned peripheral drivers to configure their
> respective SerDeses.
>
> v1:
>         - see cover letter for review comments addressed.
>
> Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
> ---
>  Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
>  drivers/phy/Kconfig                              |    8 +
>  drivers/phy/Makefile                             |    1 +
>  drivers/phy/phy-keystone-serdes.c                | 2373 ++++++++++++++++++++++
>  4 files changed, 2660 insertions(+)
>  create mode 100644 drivers/phy/phy-keystone-serdes.c
>
> diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt
> index 9cf9446..4dca271 100644
> --- a/Documentation/devicetree/bindings/phy/ti-phy.txt
> +++ b/Documentation/devicetree/bindings/phy/ti-phy.txt
> @@ -115,4 +115,282 @@ sata_phy: phy at 4A096000 {
>         clock-names = "sysclk", "refclk";
>         syscon-pllreset = <&scm_conf 0x3fc>;
>         #phy-cells = <0>;
> +
> +TI Keystone SerDes PHY
> +======================
> +
> +Required properties:
> + - compatible: should be one of
> +       * "ti,keystone-serdes-gbe"
> +       * "ti,keystone-serdes-xgbe"
> +       * "ti,keystone-serdes-pcie"

These are different blocks or different modes of the same block? It's
fine if the former. If the latter, then you should have a single
compatible and then have a mode property. Perhaps phy-connection-type
from ePAPR ethernet binding can be extended.


> + - reg:
> +       * base address and length of the SerDes register set
> + - reg-names:
> +       * "serdes"
> +               - name of the reg SerDes register set

reg-names is kind of pointless with only 1.

> + - #phy-cells:
> +       * From the generic phy bindings, must be 0;
> + - num-lanes:
> +       * Number of lanes in SerDes.
> +
> +Optional properties:
> + - syscon-peripheral:
> +       * Handle to the subsystem register region of the peripheral
> +         inside which the SerDes exists.
> + - syscon-link:
> +       * Handle to the Link register region of the peripheral inside
> +         which the SerDes exists.  Example: it is the PCSR register
> +         region in the case of 10gbe.
> + - rx-force-enable:
> +       * Include this property if receiver attenuation and boost are
> +         to be configured with specific values defined in rx-force.
> + - link-rate-kbps:
> +       * SerDes link rate to be configured, in kbps.
> +
> +
> +For gbe and 10gbe SerDes, it is optional to represent each lane as
> +a sub-node, which can be enabled or disabled individually using
> +the "status" property.
> +
> +Required properties (lane sub-node):
> + - reg:
> +       * lane number
> +
> +Optional properties (lane sub-node):
> + - control-rate:
> +       * Lane control rate
> +               0: full rate
> +               1: half rate
> +               2: quarter rate
> + - rx-start:
> +       * Initial lane rx equalizer attenuation and boost configurations.
> +       * Must be array of 2 integers.
> + - rx-force:
> +       * Forced lane rx equalizer attenuation and boost configurations.
> +       * Must be array of 2 integers.
> + - tx-coeff:
> +       * Lane c1, c2, cm, attenuation and regulator output voltage
> +         configurations.
> +       * Must be array of 5 integers.
> + - loopback:
> +       * Include this property to enable loopback at the SerDes
> +         lane level.

This seems overly complicated. Do you really expect these to be
different per lane?

> +
> +Example for Keystone K2E GBE:
> +-----------------------------
> +
> +gbe_serdes0: gbe_serdes at 232a000 {
> +       #phy-cells              = <0>;
> +       compatible              = "ti,keystone-serdes-gbe";
> +       reg                     = <0x0232a000 0x2000>;
> +       reg-names               = "serdes";
> +       link-rate-kbps          = <1250000>;
> +       num-lanes               = <4>;
> +       lanes {
> +               #address-cells = <1>;
> +               #size-cells = <0>;
> +               lane at 0 {
> +                       /*loopback;*/
> +                       reg             = <0>;
> +                       control-rate    = <2>; /* quart */
> +                       rx-start        = <7 5>;
> +                       rx-force        = <1 1>;
> +                       tx-coeff        = <0 0 0 12 4>;
> +                              /* c1 c2 cm att vreg */
> +               };
> +               lane at 1 {
> +                       /*loopback;*/
> +                       reg             = <1>;
> +                       control-rate    = <2>; /* quart */
> +                       rx-start        = <7 5>;
> +                       rx-force        = <1 1>;
> +                       tx-coeff        = <0 0 0 12 4>;
> +                              /* c1 c2 cm att vreg */
> +               };
> +       };
> +};
> +
> +gbe_serdes1: gbe_serdes at 2324000 {
> +       #phy-cells              = <0>;
> +       compatible              = "ti,keystone-serdes-gbe";
> +       reg                     = <0x02324000 0x2000>;
> +       reg-names               = "serdes";
> +       link-rate-kbps          = <1250000>;
> +       num-lanes               = <4>;

4 lanes, but only 2 child nodes?

> +       lanes {
> +               #address-cells = <1>;
> +               #size-cells = <0>;
> +               lane at 0 {
> +                       /*loopback;*/
> +                       reg             = <0>;
> +                       control-rate    = <2>; /* quart */
> +                       rx-start        = <7 5>;
> +                       rx-force        = <1 1>;
> +                       tx-coeff        = <0 0 0 12 4>;
> +                              /* c1 c2 cm att vreg */
> +               };
> +               lane at 1 {
> +                       /*loopback;*/
> +                       reg             = <1>;
> +                       control-rate    = <2>; /* quart */
> +                       rx-start        = <7 5>;
> +                       rx-force        = <1 1>;
> +                       tx-coeff        = <0 0 0 12 4>;
> +                              /* c1 c2 cm att vreg */
> +               };
> +       };
> +};
> +
> +netcp: netcp at 24000000 {
> +       ...
> +
> +       netcp-devices {
> +               ...
> +
> +               gbe at 200000 { /* ETHSS */
> +                       ...
> +                       serdeses {
> +                               #address-cells = <1>;
> +                               #size-cells = <0>;
> +                               serdes at 0 {
> +                                       reg = <0>;
> +                                       phys = <&gbe_serdes0>;
> +                                       status = "ok";
> +                               };
> +                               serdes at 1 {
> +                                       reg = <1>;
> +                                       phys = <&gbe_serdes1>;
> +                                       status = "ok";

This is way too complex. Just do:

phys = <&gbe_serdes0, &gbe_serdes1>;

in the gbe node.

Rob

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-15 16:51   ` Russell King - ARM Linux
  0 siblings, 0 replies; 63+ messages in thread
From: Russell King - ARM Linux @ 2015-10-15 16:51 UTC (permalink / raw
  To: WingMan Kwok
  Cc: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, kishon,
	rogerq, m-karicheri2, bhelgaas, ssantosh, devicetree,
	linux-kernel, linux-pci, linux-arm-kernel

On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
> On TI's Keystone platforms, several peripherals such as the
> gbe ethernet switch, 10gbe ethether switch and PCIe controller
> require the use of a SerDes for converting SoC parallel data into
> serialized data that can be output over a high-speed electrical
> interface, and also converting high-speed serial input data
> into parallel data that can be processed by the SoC.  The
> SerDeses used by those peripherals, though they may be different,
> are largely similar in functionality and setup.

Given that serdes is not specific to TI, should this be specific to
TI, or should there be an effort to come up with something which
everyone who has serdes links can make use of?

Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
plethora of SoC specific stuff for this.

When serdes is combined with SFP cages, the situation becomes much
more fun, because the serdes link then needs to become hotpluggable
(SFP modules are designed to be hotplugged) which means you have to
be able to switch between (at least) 1G SGMII and 1000base-X modes,
and probably 10G mode as well.  There's even a SFP module that has
a SATA connector on it, though I believe there's no standard for
that, and it's more a hardware hack.

I've been working in this area but from the Ethernet side on an
Armada 38x based board which has a SFP cage on it, though it's
slightly simpler there because there is no support (or I believe
any desire) to reconfigure the serdes lanes between PCI, ethernet
and SATA - that's all setup and initialised for us by uboot.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-15 16:51   ` Russell King - ARM Linux
  0 siblings, 0 replies; 63+ messages in thread
From: Russell King - ARM Linux @ 2015-10-15 16:51 UTC (permalink / raw
  To: WingMan Kwok
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, pawel.moll-5wv7dgnIgG8,
	mark.rutland-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ, kishon-l0cyMroinI0,
	rogerq-l0cyMroinI0, m-karicheri2-l0cyMroinI0,
	bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, ssantosh-DgEjT+Ai2ygdnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-pci-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
> On TI's Keystone platforms, several peripherals such as the
> gbe ethernet switch, 10gbe ethether switch and PCIe controller
> require the use of a SerDes for converting SoC parallel data into
> serialized data that can be output over a high-speed electrical
> interface, and also converting high-speed serial input data
> into parallel data that can be processed by the SoC.  The
> SerDeses used by those peripherals, though they may be different,
> are largely similar in functionality and setup.

Given that serdes is not specific to TI, should this be specific to
TI, or should there be an effort to come up with something which
everyone who has serdes links can make use of?

Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
plethora of SoC specific stuff for this.

When serdes is combined with SFP cages, the situation becomes much
more fun, because the serdes link then needs to become hotpluggable
(SFP modules are designed to be hotplugged) which means you have to
be able to switch between (at least) 1G SGMII and 1000base-X modes,
and probably 10G mode as well.  There's even a SFP module that has
a SATA connector on it, though I believe there's no standard for
that, and it's more a hardware hack.

I've been working in this area but from the Ethernet side on an
Armada 38x based board which has a SFP cage on it, though it's
slightly simpler there because there is no support (or I believe
any desire) to reconfigure the serdes lanes between PCI, ethernet
and SATA - that's all setup and initialised for us by uboot.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-15 16:51   ` Russell King - ARM Linux
  0 siblings, 0 replies; 63+ messages in thread
From: Russell King - ARM Linux @ 2015-10-15 16:51 UTC (permalink / raw
  To: linux-arm-kernel

On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
> On TI's Keystone platforms, several peripherals such as the
> gbe ethernet switch, 10gbe ethether switch and PCIe controller
> require the use of a SerDes for converting SoC parallel data into
> serialized data that can be output over a high-speed electrical
> interface, and also converting high-speed serial input data
> into parallel data that can be processed by the SoC.  The
> SerDeses used by those peripherals, though they may be different,
> are largely similar in functionality and setup.

Given that serdes is not specific to TI, should this be specific to
TI, or should there be an effort to come up with something which
everyone who has serdes links can make use of?

Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
plethora of SoC specific stuff for this.

When serdes is combined with SFP cages, the situation becomes much
more fun, because the serdes link then needs to become hotpluggable
(SFP modules are designed to be hotplugged) which means you have to
be able to switch between (at least) 1G SGMII and 1000base-X modes,
and probably 10G mode as well.  There's even a SFP module that has
a SATA connector on it, though I believe there's no standard for
that, and it's more a hardware hack.

I've been working in this area but from the Ethernet side on an
Armada 38x based board which has a SFP cage on it, though it's
slightly simpler there because there is no support (or I believe
any desire) to reconfigure the serdes lanes between PCI, ethernet
and SATA - that's all setup and initialised for us by uboot.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
  2015-10-15 16:51   ` Russell King - ARM Linux
  (?)
@ 2015-10-15 19:21     ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 63+ messages in thread
From: Kishon Vijay Abraham I @ 2015-10-15 19:21 UTC (permalink / raw
  To: Russell King - ARM Linux, WingMan Kwok
  Cc: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, rogerq,
	m-karicheri2, bhelgaas, ssantosh, devicetree, linux-kernel,
	linux-pci, linux-arm-kernel

Hi,

On Thursday 15 October 2015 10:21 PM, Russell King - ARM Linux wrote:
> On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
>> On TI's Keystone platforms, several peripherals such as the
>> gbe ethernet switch, 10gbe ethether switch and PCIe controller
>> require the use of a SerDes for converting SoC parallel data into
>> serialized data that can be output over a high-speed electrical
>> interface, and also converting high-speed serial input data
>> into parallel data that can be processed by the SoC.  The
>> SerDeses used by those peripherals, though they may be different,
>> are largely similar in functionality and setup.
> 
> Given that serdes is not specific to TI, should this be specific to
> TI, or should there be an effort to come up with something which
> everyone who has serdes links can make use of?
> 
> Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
> 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
> plethora of SoC specific stuff for this.

Generally every SoC use it's own serdes and the programming required is
different for different SoCs. Each of them have their own register map
and clock programming/regulator programming/reset programming are all
different.

However most SoC vendors use the same PHY/SerDes IP to be used by
multiple controllers like PCIe/SATA/USB in a single SoC and a single PHY
driver is used for programming all these PHYs.

Thanks
Kishon

> 
> When serdes is combined with SFP cages, the situation becomes much
> more fun, because the serdes link then needs to become hotpluggable
> (SFP modules are designed to be hotplugged) which means you have to
> be able to switch between (at least) 1G SGMII and 1000base-X modes,
> and probably 10G mode as well.  There's even a SFP module that has
> a SATA connector on it, though I believe there's no standard for
> that, and it's more a hardware hack.
> 
> I've been working in this area but from the Ethernet side on an
> Armada 38x based board which has a SFP cage on it, though it's
> slightly simpler there because there is no support (or I believe
> any desire) to reconfigure the serdes lanes between PCI, ethernet
> and SATA - that's all setup and initialised for us by uboot.
> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-15 19:21     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 63+ messages in thread
From: Kishon Vijay Abraham I @ 2015-10-15 19:21 UTC (permalink / raw
  To: Russell King - ARM Linux, WingMan Kwok
  Cc: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, rogerq,
	m-karicheri2, bhelgaas, ssantosh, devicetree, linux-kernel,
	linux-pci, linux-arm-kernel

Hi,

On Thursday 15 October 2015 10:21 PM, Russell King - ARM Linux wrote:
> On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
>> On TI's Keystone platforms, several peripherals such as the
>> gbe ethernet switch, 10gbe ethether switch and PCIe controller
>> require the use of a SerDes for converting SoC parallel data into
>> serialized data that can be output over a high-speed electrical
>> interface, and also converting high-speed serial input data
>> into parallel data that can be processed by the SoC.  The
>> SerDeses used by those peripherals, though they may be different,
>> are largely similar in functionality and setup.
> 
> Given that serdes is not specific to TI, should this be specific to
> TI, or should there be an effort to come up with something which
> everyone who has serdes links can make use of?
> 
> Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
> 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
> plethora of SoC specific stuff for this.

Generally every SoC use it's own serdes and the programming required is
different for different SoCs. Each of them have their own register map
and clock programming/regulator programming/reset programming are all
different.

However most SoC vendors use the same PHY/SerDes IP to be used by
multiple controllers like PCIe/SATA/USB in a single SoC and a single PHY
driver is used for programming all these PHYs.

Thanks
Kishon

> 
> When serdes is combined with SFP cages, the situation becomes much
> more fun, because the serdes link then needs to become hotpluggable
> (SFP modules are designed to be hotplugged) which means you have to
> be able to switch between (at least) 1G SGMII and 1000base-X modes,
> and probably 10G mode as well.  There's even a SFP module that has
> a SATA connector on it, though I believe there's no standard for
> that, and it's more a hardware hack.
> 
> I've been working in this area but from the Ethernet side on an
> Armada 38x based board which has a SFP cage on it, though it's
> slightly simpler there because there is no support (or I believe
> any desire) to reconfigure the serdes lanes between PCI, ethernet
> and SATA - that's all setup and initialised for us by uboot.
> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-15 19:21     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 63+ messages in thread
From: Kishon Vijay Abraham I @ 2015-10-15 19:21 UTC (permalink / raw
  To: linux-arm-kernel

Hi,

On Thursday 15 October 2015 10:21 PM, Russell King - ARM Linux wrote:
> On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
>> On TI's Keystone platforms, several peripherals such as the
>> gbe ethernet switch, 10gbe ethether switch and PCIe controller
>> require the use of a SerDes for converting SoC parallel data into
>> serialized data that can be output over a high-speed electrical
>> interface, and also converting high-speed serial input data
>> into parallel data that can be processed by the SoC.  The
>> SerDeses used by those peripherals, though they may be different,
>> are largely similar in functionality and setup.
> 
> Given that serdes is not specific to TI, should this be specific to
> TI, or should there be an effort to come up with something which
> everyone who has serdes links can make use of?
> 
> Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
> 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
> plethora of SoC specific stuff for this.

Generally every SoC use it's own serdes and the programming required is
different for different SoCs. Each of them have their own register map
and clock programming/regulator programming/reset programming are all
different.

However most SoC vendors use the same PHY/SerDes IP to be used by
multiple controllers like PCIe/SATA/USB in a single SoC and a single PHY
driver is used for programming all these PHYs.

Thanks
Kishon

> 
> When serdes is combined with SFP cages, the situation becomes much
> more fun, because the serdes link then needs to become hotpluggable
> (SFP modules are designed to be hotplugged) which means you have to
> be able to switch between (at least) 1G SGMII and 1000base-X modes,
> and probably 10G mode as well.  There's even a SFP module that has
> a SATA connector on it, though I believe there's no standard for
> that, and it's more a hardware hack.
> 
> I've been working in this area but from the Ethernet side on an
> Armada 38x based board which has a SFP cage on it, though it's
> slightly simpler there because there is no support (or I believe
> any desire) to reconfigure the serdes lanes between PCI, ethernet
> and SATA - that's all setup and initialised for us by uboot.
> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-15 16:01       ` Murali Karicheri
@ 2015-10-15 19:34         ` Arnd Bergmann
  -1 siblings, 0 replies; 63+ messages in thread
From: Arnd Bergmann @ 2015-10-15 19:34 UTC (permalink / raw
  To: Murali Karicheri
  Cc: linux-arm-kernel, WingMan Kwok, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, kishon, rogerq, bhelgaas, ssantosh, linux,
	devicetree, linux-kernel, linux-pci

On Thursday 15 October 2015 12:01:04 Murali Karicheri wrote:
> 
> >> + * Redistributions in binary form must reproduce the above copyright
> >> + * notice, this list of conditions and the following disclaimer in the
> >> + * documentation and/or other materials provided with the
> >> + * distribution.
> >
> > The current code does not do this when compiled, which might be a
> > problem for distributors. Can you clarify the license?
> >
> Arnd,
> 
> Can you elaborate on this? I did a grep on the string "Redistributions 
> in binary form must reproduce the above copyright" and I could find 
> several instance of this. So I am not sure what you mean by "The current 
> code does not do this when compiled".

You write that the binary form of the code must produce the copyright
notice. I don't see any code that does this. If I was looking in the
wrong place, let me know.

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 19:34         ` Arnd Bergmann
  0 siblings, 0 replies; 63+ messages in thread
From: Arnd Bergmann @ 2015-10-15 19:34 UTC (permalink / raw
  To: linux-arm-kernel

On Thursday 15 October 2015 12:01:04 Murali Karicheri wrote:
> 
> >> + * Redistributions in binary form must reproduce the above copyright
> >> + * notice, this list of conditions and the following disclaimer in the
> >> + * documentation and/or other materials provided with the
> >> + * distribution.
> >
> > The current code does not do this when compiled, which might be a
> > problem for distributors. Can you clarify the license?
> >
> Arnd,
> 
> Can you elaborate on this? I did a grep on the string "Redistributions 
> in binary form must reproduce the above copyright" and I could find 
> several instance of this. So I am not sure what you mean by "The current 
> code does not do this when compiled".

You write that the binary form of the code must produce the copyright
notice. I don't see any code that does this. If I was looking in the
wrong place, let me know.

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-15 14:51     ` Arnd Bergmann
  (?)
  (?)
@ 2015-10-15 20:08       ` Kwok, WingMan
  -1 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-15 20:08 UTC (permalink / raw
  To: Arnd Bergmann, linux-arm-kernel@lists.infradead.org
  Cc: robh+dt@kernel.org, pawel.moll@arm.com, mark.rutland@arm.com,
	ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
	KISHON VIJAY ABRAHAM, Quadros, Roger, Karicheri, Muralidharan,
	bhelgaas@google.com, ssantosh@kernel.org, linux@arm.linux.org.uk,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 5299 bytes --]

Hi,

> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd@arndb.de]
> Sent: Thursday, October 15, 2015 10:51 AM
> To: linux-arm-kernel@lists.infradead.org
> Cc: Kwok, WingMan; robh+dt@kernel.org; pawel.moll@arm.com;
> mark.rutland@arm.com; ijc+devicetree@hellion.org.uk; galak@codeaurora.org;
> KISHON VIJAY ABRAHAM; Quadros, Roger; Karicheri, Muralidharan;
> bhelgaas@google.com; ssantosh@kernel.org; linux@arm.linux.org.uk;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> pci@vger.kernel.org
> Subject: Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and
> pcie
> 
> On Thursday 15 October 2015 10:25:44 WingMan Kwok wrote:
> > On TI's Keystone platforms, several peripherals such as the
> > gbe ethernet switch, 10gbe ethernet switch and PCIe controller
> > require the use of a SerDes for converting SoC parallel data into
> > serialized data that can be output over a high-speed electrical
> > interface, and also converting high-speed serial input data
> > into parallel data that can be processed by the SoC.  The
> > SerDeses used by those peripherals, though they may be different,
> > are largely similar in functionality and setup.
> >
> > This patch provides a SerDes phy driver implementation that can be
> > used by the above mentioned peripheral drivers to configure their
> > respective SerDeses.
> >
> > v1:
> > 	- see cover letter for review comments addressed.
> >
> > Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
> > ---
> >  Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
> >  drivers/phy/Kconfig                              |    8 +
> >  drivers/phy/Makefile                             |    1 +
> >  drivers/phy/phy-keystone-serdes.c                | 2373
> ++++++++++++++++++++++
> >  4 files changed, 2660 insertions(+)
> >  create mode 100644 drivers/phy/phy-keystone-serdes.c
> 
> This is quite a bit of code. Are you very sure that this PHY is
> not used on any other SoC family, and that it is not licensed
> from a third party? I would hate to see multiple copies of
> this getting merged into the kernel over time, so thename should
> be chosen carefully to let the next person know when they have
> related hardware.
> 
> > +
> > +gbe_serdes0: gbe_serdes@232a000 {
> 
> 
> make that phy@232a000, the name should be one of the usual identifiers,
> not specific to the instance.
> 

will change to something like gbe_serdes0: phy@232a000 {};

> > +config PHY_TI_KEYSTONE_SERDES
> > +	tristate "TI Keystone SerDes PHY support"
> > +	depends on OF && ARCH_KEYSTONE
> > +	select GENERIC_PHY
> > +	help
> > +	  This option enables support for TI Keystone SerDes PHY found
> > +	  in peripherals GBE, 10GBE and PCIe.
> > +
> 
> (ARCH_KEYSTONE || COMPILE_TEST) ?
> 

will add COMPILE_TEST

> > + * Redistributions in binary form must reproduce the above copyright
> > + * notice, this list of conditions and the following disclaimer in the
> > + * documentation and/or other materials provided with the
> > + * distribution.
> 
> The current code does not do this when compiled, which might be a
> problem for distributors. Can you clarify the license?
> 

will investigate

> > +#define reg_rmw(addr, value, mask) \
> > +	__raw_writel(((__raw_readl(addr) & (~(mask))) | \
> > +			(value & (mask))), (addr))
> 
> not endian safe, and potentially racy.
> 

will change to 

#define reg_rmw(addr, value, mask) \
	writel(((readl(addr) & (~(mask))) | \
			(value & (mask))), (addr))

> > +static inline void _kserdes_reset_cdr(void __iomem *sregs, int lane)
> > +{
> > +	/* toggle signal detect */
> > +	_kserdes_force_signal_detect_low(sregs, lane);
> > +	mdelay(1);
> > +	_kserdes_force_signal_detect_high(sregs, lane);
> > +}
> 
> Can you change the code so you can use msleep(1) here?
> 

will replace delays with usleep_range()

> > +
> > +	do {
> > +		mdelay(10);
> > +		memset(lane_down, 0, sizeof(lane_down));
> > +
> > +		link_up = _kserdes_check_link_status(dev, sregs,
> > +						     pcsr_regmap, lanes,
> > +						     lanes_enable,
> > +						     current_state, lane_down);
> > +
> > +		/* if we did not get link up then wait 100ms
> > +		 * before calling it again
> > +		 */
> > +		if (link_up)
> > +			break;
> > +
> > +		for (i = 0; i < lanes; i++) {
> > +			if ((lanes_enable & (1 << i)) && lane_down[i])
> > +				dev_dbg(dev,
> > +					"XGE: detected lane down on lane %d\n",
> > +					i);
> > +		}
> > +
> > +		if (++retries > 100)
> > +			return -ETIMEDOUT;
> > +
> > +	} while (!link_up);
> 
> an more importantly here. Blocking the CPU for over one second is not good.
> 
> Any use of mdelay() should have a comment explaining why you cannot use
> msleep() in that instance.
> 

will replace delays with usleep_range()

> > +
> > +static int __init keystone_serdes_phy_init(void)
> > +{
> > +	return platform_driver_register(&kserdes_driver);
> > +}
> > +module_init(keystone_serdes_phy_init);
> > +
> > +static void __exit keystone_serdes_phy_exit(void)
> > +{
> > +	platform_driver_unregister(&kserdes_driver);
> > +}
> > +module_exit(keystone_serdes_phy_exit);
> 
> module_platform_driver()
> 	

will do.

> 	Arnd

Thanks,
WingMan
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 20:08       ` Kwok, WingMan
  0 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-15 20:08 UTC (permalink / raw
  To: Arnd Bergmann, linux-arm-kernel@lists.infradead.org
  Cc: robh+dt@kernel.org, pawel.moll@arm.com, mark.rutland@arm.com,
	ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
	KISHON VIJAY ABRAHAM, Quadros, Roger, Karicheri, Muralidharan,
	bhelgaas@google.com, ssantosh@kernel.org, linux@arm.linux.org.uk,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org

Hi,

> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd@arndb.de]
> Sent: Thursday, October 15, 2015 10:51 AM
> To: linux-arm-kernel@lists.infradead.org
> Cc: Kwok, WingMan; robh+dt@kernel.org; pawel.moll@arm.com;
> mark.rutland@arm.com; ijc+devicetree@hellion.org.uk; galak@codeaurora.org;
> KISHON VIJAY ABRAHAM; Quadros, Roger; Karicheri, Muralidharan;
> bhelgaas@google.com; ssantosh@kernel.org; linux@arm.linux.org.uk;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> pci@vger.kernel.org
> Subject: Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and
> pcie
> 
> On Thursday 15 October 2015 10:25:44 WingMan Kwok wrote:
> > On TI's Keystone platforms, several peripherals such as the
> > gbe ethernet switch, 10gbe ethernet switch and PCIe controller
> > require the use of a SerDes for converting SoC parallel data into
> > serialized data that can be output over a high-speed electrical
> > interface, and also converting high-speed serial input data
> > into parallel data that can be processed by the SoC.  The
> > SerDeses used by those peripherals, though they may be different,
> > are largely similar in functionality and setup.
> >
> > This patch provides a SerDes phy driver implementation that can be
> > used by the above mentioned peripheral drivers to configure their
> > respective SerDeses.
> >
> > v1:
> > 	- see cover letter for review comments addressed.
> >
> > Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
> > ---
> >  Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
> >  drivers/phy/Kconfig                              |    8 +
> >  drivers/phy/Makefile                             |    1 +
> >  drivers/phy/phy-keystone-serdes.c                | 2373
> ++++++++++++++++++++++
> >  4 files changed, 2660 insertions(+)
> >  create mode 100644 drivers/phy/phy-keystone-serdes.c
> 
> This is quite a bit of code. Are you very sure that this PHY is
> not used on any other SoC family, and that it is not licensed
> from a third party? I would hate to see multiple copies of
> this getting merged into the kernel over time, so thename should
> be chosen carefully to let the next person know when they have
> related hardware.
> 
> > +
> > +gbe_serdes0: gbe_serdes@232a000 {
> 
> 
> make that phy@232a000, the name should be one of the usual identifiers,
> not specific to the instance.
> 

will change to something like gbe_serdes0: phy@232a000 {};

> > +config PHY_TI_KEYSTONE_SERDES
> > +	tristate "TI Keystone SerDes PHY support"
> > +	depends on OF && ARCH_KEYSTONE
> > +	select GENERIC_PHY
> > +	help
> > +	  This option enables support for TI Keystone SerDes PHY found
> > +	  in peripherals GBE, 10GBE and PCIe.
> > +
> 
> (ARCH_KEYSTONE || COMPILE_TEST) ?
> 

will add COMPILE_TEST

> > + * Redistributions in binary form must reproduce the above copyright
> > + * notice, this list of conditions and the following disclaimer in the
> > + * documentation and/or other materials provided with the
> > + * distribution.
> 
> The current code does not do this when compiled, which might be a
> problem for distributors. Can you clarify the license?
> 

will investigate

> > +#define reg_rmw(addr, value, mask) \
> > +	__raw_writel(((__raw_readl(addr) & (~(mask))) | \
> > +			(value & (mask))), (addr))
> 
> not endian safe, and potentially racy.
> 

will change to 

#define reg_rmw(addr, value, mask) \
	writel(((readl(addr) & (~(mask))) | \
			(value & (mask))), (addr))

> > +static inline void _kserdes_reset_cdr(void __iomem *sregs, int lane)
> > +{
> > +	/* toggle signal detect */
> > +	_kserdes_force_signal_detect_low(sregs, lane);
> > +	mdelay(1);
> > +	_kserdes_force_signal_detect_high(sregs, lane);
> > +}
> 
> Can you change the code so you can use msleep(1) here?
> 

will replace delays with usleep_range()

> > +
> > +	do {
> > +		mdelay(10);
> > +		memset(lane_down, 0, sizeof(lane_down));
> > +
> > +		link_up = _kserdes_check_link_status(dev, sregs,
> > +						     pcsr_regmap, lanes,
> > +						     lanes_enable,
> > +						     current_state, lane_down);
> > +
> > +		/* if we did not get link up then wait 100ms
> > +		 * before calling it again
> > +		 */
> > +		if (link_up)
> > +			break;
> > +
> > +		for (i = 0; i < lanes; i++) {
> > +			if ((lanes_enable & (1 << i)) && lane_down[i])
> > +				dev_dbg(dev,
> > +					"XGE: detected lane down on lane %d\n",
> > +					i);
> > +		}
> > +
> > +		if (++retries > 100)
> > +			return -ETIMEDOUT;
> > +
> > +	} while (!link_up);
> 
> an more importantly here. Blocking the CPU for over one second is not good.
> 
> Any use of mdelay() should have a comment explaining why you cannot use
> msleep() in that instance.
> 

will replace delays with usleep_range()

> > +
> > +static int __init keystone_serdes_phy_init(void)
> > +{
> > +	return platform_driver_register(&kserdes_driver);
> > +}
> > +module_init(keystone_serdes_phy_init);
> > +
> > +static void __exit keystone_serdes_phy_exit(void)
> > +{
> > +	platform_driver_unregister(&kserdes_driver);
> > +}
> > +module_exit(keystone_serdes_phy_exit);
> 
> module_platform_driver()
> 	

will do.

> 	Arnd

Thanks,
WingMan

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 20:08       ` Kwok, WingMan
  0 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-15 20:08 UTC (permalink / raw
  To: linux-arm-kernel

Hi,

> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd at arndb.de]
> Sent: Thursday, October 15, 2015 10:51 AM
> To: linux-arm-kernel at lists.infradead.org
> Cc: Kwok, WingMan; robh+dt at kernel.org; pawel.moll at arm.com;
> mark.rutland at arm.com; ijc+devicetree at hellion.org.uk; galak at codeaurora.org;
> KISHON VIJAY ABRAHAM; Quadros, Roger; Karicheri, Muralidharan;
> bhelgaas at google.com; ssantosh at kernel.org; linux at arm.linux.org.uk;
> devicetree at vger.kernel.org; linux-kernel at vger.kernel.org; linux-
> pci at vger.kernel.org
> Subject: Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and
> pcie
> 
> On Thursday 15 October 2015 10:25:44 WingMan Kwok wrote:
> > On TI's Keystone platforms, several peripherals such as the
> > gbe ethernet switch, 10gbe ethernet switch and PCIe controller
> > require the use of a SerDes for converting SoC parallel data into
> > serialized data that can be output over a high-speed electrical
> > interface, and also converting high-speed serial input data
> > into parallel data that can be processed by the SoC.  The
> > SerDeses used by those peripherals, though they may be different,
> > are largely similar in functionality and setup.
> >
> > This patch provides a SerDes phy driver implementation that can be
> > used by the above mentioned peripheral drivers to configure their
> > respective SerDeses.
> >
> > v1:
> > 	- see cover letter for review comments addressed.
> >
> > Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
> > ---
> >  Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
> >  drivers/phy/Kconfig                              |    8 +
> >  drivers/phy/Makefile                             |    1 +
> >  drivers/phy/phy-keystone-serdes.c                | 2373
> ++++++++++++++++++++++
> >  4 files changed, 2660 insertions(+)
> >  create mode 100644 drivers/phy/phy-keystone-serdes.c
> 
> This is quite a bit of code. Are you very sure that this PHY is
> not used on any other SoC family, and that it is not licensed
> from a third party? I would hate to see multiple copies of
> this getting merged into the kernel over time, so thename should
> be chosen carefully to let the next person know when they have
> related hardware.
> 
> > +
> > +gbe_serdes0: gbe_serdes at 232a000 {
> 
> 
> make that phy at 232a000, the name should be one of the usual identifiers,
> not specific to the instance.
> 

will change to something like gbe_serdes0: phy at 232a000 {};

> > +config PHY_TI_KEYSTONE_SERDES
> > +	tristate "TI Keystone SerDes PHY support"
> > +	depends on OF && ARCH_KEYSTONE
> > +	select GENERIC_PHY
> > +	help
> > +	  This option enables support for TI Keystone SerDes PHY found
> > +	  in peripherals GBE, 10GBE and PCIe.
> > +
> 
> (ARCH_KEYSTONE || COMPILE_TEST) ?
> 

will add COMPILE_TEST

> > + * Redistributions in binary form must reproduce the above copyright
> > + * notice, this list of conditions and the following disclaimer in the
> > + * documentation and/or other materials provided with the
> > + * distribution.
> 
> The current code does not do this when compiled, which might be a
> problem for distributors. Can you clarify the license?
> 

will investigate

> > +#define reg_rmw(addr, value, mask) \
> > +	__raw_writel(((__raw_readl(addr) & (~(mask))) | \
> > +			(value & (mask))), (addr))
> 
> not endian safe, and potentially racy.
> 

will change to 

#define reg_rmw(addr, value, mask) \
	writel(((readl(addr) & (~(mask))) | \
			(value & (mask))), (addr))

> > +static inline void _kserdes_reset_cdr(void __iomem *sregs, int lane)
> > +{
> > +	/* toggle signal detect */
> > +	_kserdes_force_signal_detect_low(sregs, lane);
> > +	mdelay(1);
> > +	_kserdes_force_signal_detect_high(sregs, lane);
> > +}
> 
> Can you change the code so you can use msleep(1) here?
> 

will replace delays with usleep_range()

> > +
> > +	do {
> > +		mdelay(10);
> > +		memset(lane_down, 0, sizeof(lane_down));
> > +
> > +		link_up = _kserdes_check_link_status(dev, sregs,
> > +						     pcsr_regmap, lanes,
> > +						     lanes_enable,
> > +						     current_state, lane_down);
> > +
> > +		/* if we did not get link up then wait 100ms
> > +		 * before calling it again
> > +		 */
> > +		if (link_up)
> > +			break;
> > +
> > +		for (i = 0; i < lanes; i++) {
> > +			if ((lanes_enable & (1 << i)) && lane_down[i])
> > +				dev_dbg(dev,
> > +					"XGE: detected lane down on lane %d\n",
> > +					i);
> > +		}
> > +
> > +		if (++retries > 100)
> > +			return -ETIMEDOUT;
> > +
> > +	} while (!link_up);
> 
> an more importantly here. Blocking the CPU for over one second is not good.
> 
> Any use of mdelay() should have a comment explaining why you cannot use
> msleep() in that instance.
> 

will replace delays with usleep_range()

> > +
> > +static int __init keystone_serdes_phy_init(void)
> > +{
> > +	return platform_driver_register(&kserdes_driver);
> > +}
> > +module_init(keystone_serdes_phy_init);
> > +
> > +static void __exit keystone_serdes_phy_exit(void)
> > +{
> > +	platform_driver_unregister(&kserdes_driver);
> > +}
> > +module_exit(keystone_serdes_phy_exit);
> 
> module_platform_driver()
> 	

will do.

> 	Arnd

Thanks,
WingMan

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 20:08       ` Kwok, WingMan
  0 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-15 20:08 UTC (permalink / raw
  To: Arnd Bergmann, linux-arm-kernel@lists.infradead.org
  Cc: robh+dt@kernel.org, pawel.moll@arm.com, mark.rutland@arm.com,
	ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
	KISHON VIJAY ABRAHAM, Quadros, Roger, Karicheri, Muralidharan,
	bhelgaas@google.com, ssantosh@kernel.org, linux@arm.linux.org.uk,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org

SGksDQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogQXJuZCBCZXJnbWFu
biBbbWFpbHRvOmFybmRAYXJuZGIuZGVdDQo+IFNlbnQ6IFRodXJzZGF5LCBPY3RvYmVyIDE1LCAy
MDE1IDEwOjUxIEFNDQo+IFRvOiBsaW51eC1hcm0ta2VybmVsQGxpc3RzLmluZnJhZGVhZC5vcmcN
Cj4gQ2M6IEt3b2ssIFdpbmdNYW47IHJvYmgrZHRAa2VybmVsLm9yZzsgcGF3ZWwubW9sbEBhcm0u
Y29tOw0KPiBtYXJrLnJ1dGxhbmRAYXJtLmNvbTsgaWpjK2RldmljZXRyZWVAaGVsbGlvbi5vcmcu
dWs7IGdhbGFrQGNvZGVhdXJvcmEub3JnOw0KPiBLSVNIT04gVklKQVkgQUJSQUhBTTsgUXVhZHJv
cywgUm9nZXI7IEthcmljaGVyaSwgTXVyYWxpZGhhcmFuOw0KPiBiaGVsZ2Fhc0Bnb29nbGUuY29t
OyBzc2FudG9zaEBrZXJuZWwub3JnOyBsaW51eEBhcm0ubGludXgub3JnLnVrOw0KPiBkZXZpY2V0
cmVlQHZnZXIua2VybmVsLm9yZzsgbGludXgta2VybmVsQHZnZXIua2VybmVsLm9yZzsgbGludXgt
DQo+IHBjaUB2Z2VyLmtlcm5lbC5vcmcNCj4gU3ViamVjdDogUmU6IFtQQVRDSCB2MSAxLzJdIHBo
eToga2V5c3RvbmU6IHNlcmRlcyBkcml2ZXIgZm9yIGdiZSAxMGdiZSBhbmQNCj4gcGNpZQ0KPiAN
Cj4gT24gVGh1cnNkYXkgMTUgT2N0b2JlciAyMDE1IDEwOjI1OjQ0IFdpbmdNYW4gS3dvayB3cm90
ZToNCj4gPiBPbiBUSSdzIEtleXN0b25lIHBsYXRmb3Jtcywgc2V2ZXJhbCBwZXJpcGhlcmFscyBz
dWNoIGFzIHRoZQ0KPiA+IGdiZSBldGhlcm5ldCBzd2l0Y2gsIDEwZ2JlIGV0aGVybmV0IHN3aXRj
aCBhbmQgUENJZSBjb250cm9sbGVyDQo+ID4gcmVxdWlyZSB0aGUgdXNlIG9mIGEgU2VyRGVzIGZv
ciBjb252ZXJ0aW5nIFNvQyBwYXJhbGxlbCBkYXRhIGludG8NCj4gPiBzZXJpYWxpemVkIGRhdGEg
dGhhdCBjYW4gYmUgb3V0cHV0IG92ZXIgYSBoaWdoLXNwZWVkIGVsZWN0cmljYWwNCj4gPiBpbnRl
cmZhY2UsIGFuZCBhbHNvIGNvbnZlcnRpbmcgaGlnaC1zcGVlZCBzZXJpYWwgaW5wdXQgZGF0YQ0K
PiA+IGludG8gcGFyYWxsZWwgZGF0YSB0aGF0IGNhbiBiZSBwcm9jZXNzZWQgYnkgdGhlIFNvQy4g
IFRoZQ0KPiA+IFNlckRlc2VzIHVzZWQgYnkgdGhvc2UgcGVyaXBoZXJhbHMsIHRob3VnaCB0aGV5
IG1heSBiZSBkaWZmZXJlbnQsDQo+ID4gYXJlIGxhcmdlbHkgc2ltaWxhciBpbiBmdW5jdGlvbmFs
aXR5IGFuZCBzZXR1cC4NCj4gPg0KPiA+IFRoaXMgcGF0Y2ggcHJvdmlkZXMgYSBTZXJEZXMgcGh5
IGRyaXZlciBpbXBsZW1lbnRhdGlvbiB0aGF0IGNhbiBiZQ0KPiA+IHVzZWQgYnkgdGhlIGFib3Zl
IG1lbnRpb25lZCBwZXJpcGhlcmFsIGRyaXZlcnMgdG8gY29uZmlndXJlIHRoZWlyDQo+ID4gcmVz
cGVjdGl2ZSBTZXJEZXNlcy4NCj4gPg0KPiA+IHYxOg0KPiA+IAktIHNlZSBjb3ZlciBsZXR0ZXIg
Zm9yIHJldmlldyBjb21tZW50cyBhZGRyZXNzZWQuDQo+ID4NCj4gPiBTaWduZWQtb2ZmLWJ5OiBX
aW5nTWFuIEt3b2sgPHcta3dvazJAdGkuY29tPg0KPiA+IC0tLQ0KPiA+ICBEb2N1bWVudGF0aW9u
L2RldmljZXRyZWUvYmluZGluZ3MvcGh5L3RpLXBoeS50eHQgfCAgMjc4ICsrKw0KPiA+ICBkcml2
ZXJzL3BoeS9LY29uZmlnICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICA4ICsNCj4g
PiAgZHJpdmVycy9waHkvTWFrZWZpbGUgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAg
MSArDQo+ID4gIGRyaXZlcnMvcGh5L3BoeS1rZXlzdG9uZS1zZXJkZXMuYyAgICAgICAgICAgICAg
ICB8IDIzNzMNCj4gKysrKysrKysrKysrKysrKysrKysrKw0KPiA+ICA0IGZpbGVzIGNoYW5nZWQs
IDI2NjAgaW5zZXJ0aW9ucygrKQ0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9waHkv
cGh5LWtleXN0b25lLXNlcmRlcy5jDQo+IA0KPiBUaGlzIGlzIHF1aXRlIGEgYml0IG9mIGNvZGUu
IEFyZSB5b3UgdmVyeSBzdXJlIHRoYXQgdGhpcyBQSFkgaXMNCj4gbm90IHVzZWQgb24gYW55IG90
aGVyIFNvQyBmYW1pbHksIGFuZCB0aGF0IGl0IGlzIG5vdCBsaWNlbnNlZA0KPiBmcm9tIGEgdGhp
cmQgcGFydHk/IEkgd291bGQgaGF0ZSB0byBzZWUgbXVsdGlwbGUgY29waWVzIG9mDQo+IHRoaXMg
Z2V0dGluZyBtZXJnZWQgaW50byB0aGUga2VybmVsIG92ZXIgdGltZSwgc28gdGhlbmFtZSBzaG91
bGQNCj4gYmUgY2hvc2VuIGNhcmVmdWxseSB0byBsZXQgdGhlIG5leHQgcGVyc29uIGtub3cgd2hl
biB0aGV5IGhhdmUNCj4gcmVsYXRlZCBoYXJkd2FyZS4NCj4gDQo+ID4gKw0KPiA+ICtnYmVfc2Vy
ZGVzMDogZ2JlX3NlcmRlc0AyMzJhMDAwIHsNCj4gDQo+IA0KPiBtYWtlIHRoYXQgcGh5QDIzMmEw
MDAsIHRoZSBuYW1lIHNob3VsZCBiZSBvbmUgb2YgdGhlIHVzdWFsIGlkZW50aWZpZXJzLA0KPiBu
b3Qgc3BlY2lmaWMgdG8gdGhlIGluc3RhbmNlLg0KPiANCg0Kd2lsbCBjaGFuZ2UgdG8gc29tZXRo
aW5nIGxpa2UgZ2JlX3NlcmRlczA6IHBoeUAyMzJhMDAwIHt9Ow0KDQo+ID4gK2NvbmZpZyBQSFlf
VElfS0VZU1RPTkVfU0VSREVTDQo+ID4gKwl0cmlzdGF0ZSAiVEkgS2V5c3RvbmUgU2VyRGVzIFBI
WSBzdXBwb3J0Ig0KPiA+ICsJZGVwZW5kcyBvbiBPRiAmJiBBUkNIX0tFWVNUT05FDQo+ID4gKwlz
ZWxlY3QgR0VORVJJQ19QSFkNCj4gPiArCWhlbHANCj4gPiArCSAgVGhpcyBvcHRpb24gZW5hYmxl
cyBzdXBwb3J0IGZvciBUSSBLZXlzdG9uZSBTZXJEZXMgUEhZIGZvdW5kDQo+ID4gKwkgIGluIHBl
cmlwaGVyYWxzIEdCRSwgMTBHQkUgYW5kIFBDSWUuDQo+ID4gKw0KPiANCj4gKEFSQ0hfS0VZU1RP
TkUgfHwgQ09NUElMRV9URVNUKSA/DQo+IA0KDQp3aWxsIGFkZCBDT01QSUxFX1RFU1QNCg0KPiA+
ICsgKiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFi
b3ZlIGNvcHlyaWdodA0KPiA+ICsgKiBub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFu
ZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIgaW4gdGhlDQo+ID4gKyAqIGRvY3VtZW50YXRpb24g
YW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92aWRlZCB3aXRoIHRoZQ0KPiA+ICsgKiBkaXN0cmli
dXRpb24uDQo+IA0KPiBUaGUgY3VycmVudCBjb2RlIGRvZXMgbm90IGRvIHRoaXMgd2hlbiBjb21w
aWxlZCwgd2hpY2ggbWlnaHQgYmUgYQ0KPiBwcm9ibGVtIGZvciBkaXN0cmlidXRvcnMuIENhbiB5
b3UgY2xhcmlmeSB0aGUgbGljZW5zZT8NCj4gDQoNCndpbGwgaW52ZXN0aWdhdGUNCg0KPiA+ICsj
ZGVmaW5lIHJlZ19ybXcoYWRkciwgdmFsdWUsIG1hc2spIFwNCj4gPiArCV9fcmF3X3dyaXRlbCgo
KF9fcmF3X3JlYWRsKGFkZHIpICYgKH4obWFzaykpKSB8IFwNCj4gPiArCQkJKHZhbHVlICYgKG1h
c2spKSksIChhZGRyKSkNCj4gDQo+IG5vdCBlbmRpYW4gc2FmZSwgYW5kIHBvdGVudGlhbGx5IHJh
Y3kuDQo+IA0KDQp3aWxsIGNoYW5nZSB0byANCg0KI2RlZmluZSByZWdfcm13KGFkZHIsIHZhbHVl
LCBtYXNrKSBcDQoJd3JpdGVsKCgocmVhZGwoYWRkcikgJiAofihtYXNrKSkpIHwgXA0KCQkJKHZh
bHVlICYgKG1hc2spKSksIChhZGRyKSkNCg0KPiA+ICtzdGF0aWMgaW5saW5lIHZvaWQgX2tzZXJk
ZXNfcmVzZXRfY2RyKHZvaWQgX19pb21lbSAqc3JlZ3MsIGludCBsYW5lKQ0KPiA+ICt7DQo+ID4g
KwkvKiB0b2dnbGUgc2lnbmFsIGRldGVjdCAqLw0KPiA+ICsJX2tzZXJkZXNfZm9yY2Vfc2lnbmFs
X2RldGVjdF9sb3coc3JlZ3MsIGxhbmUpOw0KPiA+ICsJbWRlbGF5KDEpOw0KPiA+ICsJX2tzZXJk
ZXNfZm9yY2Vfc2lnbmFsX2RldGVjdF9oaWdoKHNyZWdzLCBsYW5lKTsNCj4gPiArfQ0KPiANCj4g
Q2FuIHlvdSBjaGFuZ2UgdGhlIGNvZGUgc28geW91IGNhbiB1c2UgbXNsZWVwKDEpIGhlcmU/DQo+
IA0KDQp3aWxsIHJlcGxhY2UgZGVsYXlzIHdpdGggdXNsZWVwX3JhbmdlKCkNCg0KPiA+ICsNCj4g
PiArCWRvIHsNCj4gPiArCQltZGVsYXkoMTApOw0KPiA+ICsJCW1lbXNldChsYW5lX2Rvd24sIDAs
IHNpemVvZihsYW5lX2Rvd24pKTsNCj4gPiArDQo+ID4gKwkJbGlua191cCA9IF9rc2VyZGVzX2No
ZWNrX2xpbmtfc3RhdHVzKGRldiwgc3JlZ3MsDQo+ID4gKwkJCQkJCSAgICAgcGNzcl9yZWdtYXAs
IGxhbmVzLA0KPiA+ICsJCQkJCQkgICAgIGxhbmVzX2VuYWJsZSwNCj4gPiArCQkJCQkJICAgICBj
dXJyZW50X3N0YXRlLCBsYW5lX2Rvd24pOw0KPiA+ICsNCj4gPiArCQkvKiBpZiB3ZSBkaWQgbm90
IGdldCBsaW5rIHVwIHRoZW4gd2FpdCAxMDBtcw0KPiA+ICsJCSAqIGJlZm9yZSBjYWxsaW5nIGl0
IGFnYWluDQo+ID4gKwkJICovDQo+ID4gKwkJaWYgKGxpbmtfdXApDQo+ID4gKwkJCWJyZWFrOw0K
PiA+ICsNCj4gPiArCQlmb3IgKGkgPSAwOyBpIDwgbGFuZXM7IGkrKykgew0KPiA+ICsJCQlpZiAo
KGxhbmVzX2VuYWJsZSAmICgxIDw8IGkpKSAmJiBsYW5lX2Rvd25baV0pDQo+ID4gKwkJCQlkZXZf
ZGJnKGRldiwNCj4gPiArCQkJCQkiWEdFOiBkZXRlY3RlZCBsYW5lIGRvd24gb24gbGFuZSAlZFxu
IiwNCj4gPiArCQkJCQlpKTsNCj4gPiArCQl9DQo+ID4gKw0KPiA+ICsJCWlmICgrK3JldHJpZXMg
PiAxMDApDQo+ID4gKwkJCXJldHVybiAtRVRJTUVET1VUOw0KPiA+ICsNCj4gPiArCX0gd2hpbGUg
KCFsaW5rX3VwKTsNCj4gDQo+IGFuIG1vcmUgaW1wb3J0YW50bHkgaGVyZS4gQmxvY2tpbmcgdGhl
IENQVSBmb3Igb3ZlciBvbmUgc2Vjb25kIGlzIG5vdCBnb29kLg0KPiANCj4gQW55IHVzZSBvZiBt
ZGVsYXkoKSBzaG91bGQgaGF2ZSBhIGNvbW1lbnQgZXhwbGFpbmluZyB3aHkgeW91IGNhbm5vdCB1
c2UNCj4gbXNsZWVwKCkgaW4gdGhhdCBpbnN0YW5jZS4NCj4gDQoNCndpbGwgcmVwbGFjZSBkZWxh
eXMgd2l0aCB1c2xlZXBfcmFuZ2UoKQ0KDQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IF9faW5pdCBr
ZXlzdG9uZV9zZXJkZXNfcGh5X2luaXQodm9pZCkNCj4gPiArew0KPiA+ICsJcmV0dXJuIHBsYXRm
b3JtX2RyaXZlcl9yZWdpc3Rlcigma3NlcmRlc19kcml2ZXIpOw0KPiA+ICt9DQo+ID4gK21vZHVs
ZV9pbml0KGtleXN0b25lX3NlcmRlc19waHlfaW5pdCk7DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9p
ZCBfX2V4aXQga2V5c3RvbmVfc2VyZGVzX3BoeV9leGl0KHZvaWQpDQo+ID4gK3sNCj4gPiArCXBs
YXRmb3JtX2RyaXZlcl91bnJlZ2lzdGVyKCZrc2VyZGVzX2RyaXZlcik7DQo+ID4gK30NCj4gPiAr
bW9kdWxlX2V4aXQoa2V5c3RvbmVfc2VyZGVzX3BoeV9leGl0KTsNCj4gDQo+IG1vZHVsZV9wbGF0
Zm9ybV9kcml2ZXIoKQ0KPiAJDQoNCndpbGwgZG8uDQoNCj4gCUFybmQNCg0KVGhhbmtzLA0KV2lu
Z01hbg0K

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-15 20:08       ` Kwok, WingMan
@ 2015-10-15 20:53         ` Arnd Bergmann
  -1 siblings, 0 replies; 63+ messages in thread
From: Arnd Bergmann @ 2015-10-15 20:53 UTC (permalink / raw
  To: Kwok, WingMan
  Cc: linux-arm-kernel@lists.infradead.org, robh+dt@kernel.org,
	pawel.moll@arm.com, mark.rutland@arm.com,
	ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
	KISHON VIJAY ABRAHAM, Quadros, Roger, Karicheri, Muralidharan,
	bhelgaas@google.com, ssantosh@kernel.org, linux@arm.linux.org.uk,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org

On Thursday 15 October 2015 20:08:32 Kwok, WingMan wrote:
> 
> > > +#define reg_rmw(addr, value, mask) \
> > > +   __raw_writel(((__raw_readl(addr) & (~(mask))) | \
> > > +                   (value & (mask))), (addr))
> > 
> > not endian safe, and potentially racy.
> > 
> 
> will change to 
> 
> #define reg_rmw(addr, value, mask) \
>         writel(((readl(addr) & (~(mask))) | \
>                         (value & (mask))), (addr))

Ok, sounds good. Note that if any of this is performance critical,
better use readl_relaxed(), but as long as this is just for setup
code and not for data transfers, staying with readl() as you
suggest is better.

> > > +static inline void _kserdes_reset_cdr(void __iomem *sregs, int lane)
> > > +{
> > > +   /* toggle signal detect */
> > > +   _kserdes_force_signal_detect_low(sregs, lane);
> > > +   mdelay(1);
> > > +   _kserdes_force_signal_detect_high(sregs, lane);
> > > +}
> > 
> > Can you change the code so you can use msleep(1) here?
> > 
> 
> will replace delays with usleep_range()

Ok.

> > > +
> > > +   do {
> > > +           mdelay(10);
> > > +           memset(lane_down, 0, sizeof(lane_down));
> > > +
> > > +           link_up = _kserdes_check_link_status(dev, sregs,
> > > +                                                pcsr_regmap, lanes,
> > > +                                                lanes_enable,
> > > +                                                current_state, lane_down);
> > > +
> > > +           /* if we did not get link up then wait 100ms
> > > +            * before calling it again
> > > +            */
> > > +           if (link_up)
> > > +                   break;
> > > +
> > > +           for (i = 0; i < lanes; i++) {
> > > +                   if ((lanes_enable & (1 << i)) && lane_down[i])
> > > +                           dev_dbg(dev,
> > > +                                   "XGE: detected lane down on lane %d\n",
> > > +                                   i);
> > > +           }
> > > +
> > > +           if (++retries > 100)
> > > +                   return -ETIMEDOUT;
> > > +
> > > +   } while (!link_up);
> > 
> > an more importantly here. Blocking the CPU for over one second is not good.
> > 
> > Any use of mdelay() should have a comment explaining why you cannot use
> > msleep() in that instance.
> > 
> 
> will replace delays with usleep_range()

Here you have to be careful with the total runtime. Using usleep_range()
is a good idea, and you can have a particularly wide range, but then you
should changen the timeout condition from number of retries to total
elapsed time like

	unsigned long timeout = jiffies + HZ; /* 1 second maximum */
	do {
		...

		if (link_up)
			break;

		if (time_after(jiffies, timeout)
			return -ETIMEOUT;

		usleep_range(1000, 50000);
	} while (1);

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 20:53         ` Arnd Bergmann
  0 siblings, 0 replies; 63+ messages in thread
From: Arnd Bergmann @ 2015-10-15 20:53 UTC (permalink / raw
  To: linux-arm-kernel

On Thursday 15 October 2015 20:08:32 Kwok, WingMan wrote:
> 
> > > +#define reg_rmw(addr, value, mask) \
> > > +   __raw_writel(((__raw_readl(addr) & (~(mask))) | \
> > > +                   (value & (mask))), (addr))
> > 
> > not endian safe, and potentially racy.
> > 
> 
> will change to 
> 
> #define reg_rmw(addr, value, mask) \
>         writel(((readl(addr) & (~(mask))) | \
>                         (value & (mask))), (addr))

Ok, sounds good. Note that if any of this is performance critical,
better use readl_relaxed(), but as long as this is just for setup
code and not for data transfers, staying with readl() as you
suggest is better.

> > > +static inline void _kserdes_reset_cdr(void __iomem *sregs, int lane)
> > > +{
> > > +   /* toggle signal detect */
> > > +   _kserdes_force_signal_detect_low(sregs, lane);
> > > +   mdelay(1);
> > > +   _kserdes_force_signal_detect_high(sregs, lane);
> > > +}
> > 
> > Can you change the code so you can use msleep(1) here?
> > 
> 
> will replace delays with usleep_range()

Ok.

> > > +
> > > +   do {
> > > +           mdelay(10);
> > > +           memset(lane_down, 0, sizeof(lane_down));
> > > +
> > > +           link_up = _kserdes_check_link_status(dev, sregs,
> > > +                                                pcsr_regmap, lanes,
> > > +                                                lanes_enable,
> > > +                                                current_state, lane_down);
> > > +
> > > +           /* if we did not get link up then wait 100ms
> > > +            * before calling it again
> > > +            */
> > > +           if (link_up)
> > > +                   break;
> > > +
> > > +           for (i = 0; i < lanes; i++) {
> > > +                   if ((lanes_enable & (1 << i)) && lane_down[i])
> > > +                           dev_dbg(dev,
> > > +                                   "XGE: detected lane down on lane %d\n",
> > > +                                   i);
> > > +           }
> > > +
> > > +           if (++retries > 100)
> > > +                   return -ETIMEDOUT;
> > > +
> > > +   } while (!link_up);
> > 
> > an more importantly here. Blocking the CPU for over one second is not good.
> > 
> > Any use of mdelay() should have a comment explaining why you cannot use
> > msleep() in that instance.
> > 
> 
> will replace delays with usleep_range()

Here you have to be careful with the total runtime. Using usleep_range()
is a good idea, and you can have a particularly wide range, but then you
should changen the timeout condition from number of retries to total
elapsed time like

	unsigned long timeout = jiffies + HZ; /* 1 second maximum */
	do {
		...

		if (link_up)
			break;

		if (time_after(jiffies, timeout)
			return -ETIMEOUT;

		usleep_range(1000, 50000);
	} while (1);

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-15 16:14     ` Rob Herring
  (?)
  (?)
@ 2015-10-15 23:53       ` Kwok, WingMan
  -1 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-15 23:53 UTC (permalink / raw
  To: Rob Herring
  Cc: Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	KISHON VIJAY ABRAHAM, Quadros, Roger, Karicheri, Muralidharan,
	Bjorn Helgaas, Santosh Shilimkar, Russell King - ARM Linux,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 9402 bytes --]

Hello,

> -----Original Message-----
> From: Rob Herring [mailto:robh+dt@kernel.org]
> Sent: Thursday, October 15, 2015 12:15 PM
> To: Kwok, WingMan
> Cc: Pawel Moll; Mark Rutland; Ian Campbell; Kumar Gala; KISHON VIJAY ABRAHAM;
> Quadros, Roger; Karicheri, Muralidharan; Bjorn Helgaas; Santosh Shilimkar;
> Russell King - ARM Linux; devicetree@vger.kernel.org; linux-
> kernel@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-
> kernel@lists.infradead.org
> Subject: Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and
> pcie
> 
> On Thu, Oct 15, 2015 at 9:25 AM, WingMan Kwok <w-kwok2@ti.com> wrote:
> > On TI's Keystone platforms, several peripherals such as the
> > gbe ethernet switch, 10gbe ethernet switch and PCIe controller
> > require the use of a SerDes for converting SoC parallel data into
> > serialized data that can be output over a high-speed electrical
> > interface, and also converting high-speed serial input data
> > into parallel data that can be processed by the SoC.  The
> > SerDeses used by those peripherals, though they may be different,
> > are largely similar in functionality and setup.
> >
> > This patch provides a SerDes phy driver implementation that can be
> > used by the above mentioned peripheral drivers to configure their
> > respective SerDeses.
> >
> > v1:
> >         - see cover letter for review comments addressed.
> >
> > Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
> > ---
> >  Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
> >  drivers/phy/Kconfig                              |    8 +
> >  drivers/phy/Makefile                             |    1 +
> >  drivers/phy/phy-keystone-serdes.c                | 2373
> ++++++++++++++++++++++
> >  4 files changed, 2660 insertions(+)
> >  create mode 100644 drivers/phy/phy-keystone-serdes.c
> >
> > diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt
> b/Documentation/devicetree/bindings/phy/ti-phy.txt
> > index 9cf9446..4dca271 100644
> > --- a/Documentation/devicetree/bindings/phy/ti-phy.txt
> > +++ b/Documentation/devicetree/bindings/phy/ti-phy.txt
> > @@ -115,4 +115,282 @@ sata_phy: phy@4A096000 {
> >         clock-names = "sysclk", "refclk";
> >         syscon-pllreset = <&scm_conf 0x3fc>;
> >         #phy-cells = <0>;
> > +
> > +TI Keystone SerDes PHY
> > +======================
> > +
> > +Required properties:
> > + - compatible: should be one of
> > +       * "ti,keystone-serdes-gbe"
> > +       * "ti,keystone-serdes-xgbe"
> > +       * "ti,keystone-serdes-pcie"
> 
> These are different blocks or different modes of the same block? It's
> fine if the former. If the latter, then you should have a single
> compatible and then have a mode property. Perhaps phy-connection-type
> from ePAPR ethernet binding can be extended.
> 

these are different hw blocks configured specifically
for the corresponding peripheral.

> 
> > + - reg:
> > +       * base address and length of the SerDes register set
> > + - reg-names:
> > +       * "serdes"
> > +               - name of the reg SerDes register set
> 
> reg-names is kind of pointless with only 1.
> 

will remove.

> > + - #phy-cells:
> > +       * From the generic phy bindings, must be 0;
> > + - num-lanes:
> > +       * Number of lanes in SerDes.
> > +
> > +Optional properties:
> > + - syscon-peripheral:
> > +       * Handle to the subsystem register region of the peripheral
> > +         inside which the SerDes exists.
> > + - syscon-link:
> > +       * Handle to the Link register region of the peripheral inside
> > +         which the SerDes exists.  Example: it is the PCSR register
> > +         region in the case of 10gbe.
> > + - rx-force-enable:
> > +       * Include this property if receiver attenuation and boost are
> > +         to be configured with specific values defined in rx-force.
> > + - link-rate-kbps:
> > +       * SerDes link rate to be configured, in kbps.
> > +
> > +
> > +For gbe and 10gbe SerDes, it is optional to represent each lane as
> > +a sub-node, which can be enabled or disabled individually using
> > +the "status" property.
> > +
> > +Required properties (lane sub-node):
> > + - reg:
> > +       * lane number
> > +
> > +Optional properties (lane sub-node):
> > + - control-rate:
> > +       * Lane control rate
> > +               0: full rate
> > +               1: half rate
> > +               2: quarter rate
> > + - rx-start:
> > +       * Initial lane rx equalizer attenuation and boost configurations.
> > +       * Must be array of 2 integers.
> > + - rx-force:
> > +       * Forced lane rx equalizer attenuation and boost configurations.
> > +       * Must be array of 2 integers.
> > + - tx-coeff:
> > +       * Lane c1, c2, cm, attenuation and regulator output voltage
> > +         configurations.
> > +       * Must be array of 5 integers.
> > + - loopback:
> > +       * Include this property to enable loopback at the SerDes
> > +         lane level.
> 
> This seems overly complicated. Do you really expect these to be
> different per lane?
> 

It is an requirement that each lane can be enabled/disabled
and configured individually.  Also it is potentially possible
that some of them are different due to calibration results.

> > +
> > +Example for Keystone K2E GBE:
> > +-----------------------------
> > +
> > +gbe_serdes0: gbe_serdes@232a000 {
> > +       #phy-cells              = <0>;
> > +       compatible              = "ti,keystone-serdes-gbe";
> > +       reg                     = <0x0232a000 0x2000>;
> > +       reg-names               = "serdes";
> > +       link-rate-kbps          = <1250000>;
> > +       num-lanes               = <4>;
> > +       lanes {
> > +               #address-cells = <1>;
> > +               #size-cells = <0>;
> > +               lane@0 {
> > +                       /*loopback;*/
> > +                       reg             = <0>;
> > +                       control-rate    = <2>; /* quart */
> > +                       rx-start        = <7 5>;
> > +                       rx-force        = <1 1>;
> > +                       tx-coeff        = <0 0 0 12 4>;
> > +                              /* c1 c2 cm att vreg */
> > +               };
> > +               lane@1 {
> > +                       /*loopback;*/
> > +                       reg             = <1>;
> > +                       control-rate    = <2>; /* quart */
> > +                       rx-start        = <7 5>;
> > +                       rx-force        = <1 1>;
> > +                       tx-coeff        = <0 0 0 12 4>;
> > +                              /* c1 c2 cm att vreg */
> > +               };
> > +       };
> > +};
> > +
> > +gbe_serdes1: gbe_serdes@2324000 {
> > +       #phy-cells              = <0>;
> > +       compatible              = "ti,keystone-serdes-gbe";
> > +       reg                     = <0x02324000 0x2000>;
> > +       reg-names               = "serdes";
> > +       link-rate-kbps          = <1250000>;
> > +       num-lanes               = <4>;
> 
> 4 lanes, but only 2 child nodes?
> 

since each lane can be enabled/disabled individually, a disabled
lane can have a node defined but with a status = "disabled" or
does not have a lane node defined at all.  this example shows the
latter.

> > +       lanes {
> > +               #address-cells = <1>;
> > +               #size-cells = <0>;
> > +               lane@0 {
> > +                       /*loopback;*/
> > +                       reg             = <0>;
> > +                       control-rate    = <2>; /* quart */
> > +                       rx-start        = <7 5>;
> > +                       rx-force        = <1 1>;
> > +                       tx-coeff        = <0 0 0 12 4>;
> > +                              /* c1 c2 cm att vreg */
> > +               };
> > +               lane@1 {
> > +                       /*loopback;*/
> > +                       reg             = <1>;
> > +                       control-rate    = <2>; /* quart */
> > +                       rx-start        = <7 5>;
> > +                       rx-force        = <1 1>;
> > +                       tx-coeff        = <0 0 0 12 4>;
> > +                              /* c1 c2 cm att vreg */
> > +               };
> > +       };
> > +};
> > +
> > +netcp: netcp@24000000 {
> > +       ...
> > +
> > +       netcp-devices {
> > +               ...
> > +
> > +               gbe@200000 { /* ETHSS */
> > +                       ...
> > +                       serdeses {
> > +                               #address-cells = <1>;
> > +                               #size-cells = <0>;
> > +                               serdes@0 {
> > +                                       reg = <0>;
> > +                                       phys = <&gbe_serdes0>;
> > +                                       status = "ok";
> > +                               };
> > +                               serdes@1 {
> > +                                       reg = <1>;
> > +                                       phys = <&gbe_serdes1>;
> > +                                       status = "ok";
> 
> This is way too complex. Just do:
> 
> phys = <&gbe_serdes0, &gbe_serdes1>;
> 
> in the gbe node.
> 

good point. will change to phys = <&gbe_serdes0>, <&gbe_serdes1>;

> Rob

Thanks,
WingMan
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 23:53       ` Kwok, WingMan
  0 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-15 23:53 UTC (permalink / raw
  To: Rob Herring
  Cc: Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	KISHON VIJAY ABRAHAM, Quadros, Roger, Karicheri, Muralidharan,
	Bjorn Helgaas, Santosh Shilimkar, Russell King - ARM Linux,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org

Hello,

> -----Original Message-----
> From: Rob Herring [mailto:robh+dt@kernel.org]
> Sent: Thursday, October 15, 2015 12:15 PM
> To: Kwok, WingMan
> Cc: Pawel Moll; Mark Rutland; Ian Campbell; Kumar Gala; KISHON VIJAY ABRAHAM;
> Quadros, Roger; Karicheri, Muralidharan; Bjorn Helgaas; Santosh Shilimkar;
> Russell King - ARM Linux; devicetree@vger.kernel.org; linux-
> kernel@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-
> kernel@lists.infradead.org
> Subject: Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and
> pcie
> 
> On Thu, Oct 15, 2015 at 9:25 AM, WingMan Kwok <w-kwok2@ti.com> wrote:
> > On TI's Keystone platforms, several peripherals such as the
> > gbe ethernet switch, 10gbe ethernet switch and PCIe controller
> > require the use of a SerDes for converting SoC parallel data into
> > serialized data that can be output over a high-speed electrical
> > interface, and also converting high-speed serial input data
> > into parallel data that can be processed by the SoC.  The
> > SerDeses used by those peripherals, though they may be different,
> > are largely similar in functionality and setup.
> >
> > This patch provides a SerDes phy driver implementation that can be
> > used by the above mentioned peripheral drivers to configure their
> > respective SerDeses.
> >
> > v1:
> >         - see cover letter for review comments addressed.
> >
> > Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
> > ---
> >  Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
> >  drivers/phy/Kconfig                              |    8 +
> >  drivers/phy/Makefile                             |    1 +
> >  drivers/phy/phy-keystone-serdes.c                | 2373
> ++++++++++++++++++++++
> >  4 files changed, 2660 insertions(+)
> >  create mode 100644 drivers/phy/phy-keystone-serdes.c
> >
> > diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt
> b/Documentation/devicetree/bindings/phy/ti-phy.txt
> > index 9cf9446..4dca271 100644
> > --- a/Documentation/devicetree/bindings/phy/ti-phy.txt
> > +++ b/Documentation/devicetree/bindings/phy/ti-phy.txt
> > @@ -115,4 +115,282 @@ sata_phy: phy@4A096000 {
> >         clock-names = "sysclk", "refclk";
> >         syscon-pllreset = <&scm_conf 0x3fc>;
> >         #phy-cells = <0>;
> > +
> > +TI Keystone SerDes PHY
> > +======================
> > +
> > +Required properties:
> > + - compatible: should be one of
> > +       * "ti,keystone-serdes-gbe"
> > +       * "ti,keystone-serdes-xgbe"
> > +       * "ti,keystone-serdes-pcie"
> 
> These are different blocks or different modes of the same block? It's
> fine if the former. If the latter, then you should have a single
> compatible and then have a mode property. Perhaps phy-connection-type
> from ePAPR ethernet binding can be extended.
> 

these are different hw blocks configured specifically
for the corresponding peripheral.

> 
> > + - reg:
> > +       * base address and length of the SerDes register set
> > + - reg-names:
> > +       * "serdes"
> > +               - name of the reg SerDes register set
> 
> reg-names is kind of pointless with only 1.
> 

will remove.

> > + - #phy-cells:
> > +       * From the generic phy bindings, must be 0;
> > + - num-lanes:
> > +       * Number of lanes in SerDes.
> > +
> > +Optional properties:
> > + - syscon-peripheral:
> > +       * Handle to the subsystem register region of the peripheral
> > +         inside which the SerDes exists.
> > + - syscon-link:
> > +       * Handle to the Link register region of the peripheral inside
> > +         which the SerDes exists.  Example: it is the PCSR register
> > +         region in the case of 10gbe.
> > + - rx-force-enable:
> > +       * Include this property if receiver attenuation and boost are
> > +         to be configured with specific values defined in rx-force.
> > + - link-rate-kbps:
> > +       * SerDes link rate to be configured, in kbps.
> > +
> > +
> > +For gbe and 10gbe SerDes, it is optional to represent each lane as
> > +a sub-node, which can be enabled or disabled individually using
> > +the "status" property.
> > +
> > +Required properties (lane sub-node):
> > + - reg:
> > +       * lane number
> > +
> > +Optional properties (lane sub-node):
> > + - control-rate:
> > +       * Lane control rate
> > +               0: full rate
> > +               1: half rate
> > +               2: quarter rate
> > + - rx-start:
> > +       * Initial lane rx equalizer attenuation and boost configurations.
> > +       * Must be array of 2 integers.
> > + - rx-force:
> > +       * Forced lane rx equalizer attenuation and boost configurations.
> > +       * Must be array of 2 integers.
> > + - tx-coeff:
> > +       * Lane c1, c2, cm, attenuation and regulator output voltage
> > +         configurations.
> > +       * Must be array of 5 integers.
> > + - loopback:
> > +       * Include this property to enable loopback at the SerDes
> > +         lane level.
> 
> This seems overly complicated. Do you really expect these to be
> different per lane?
> 

It is an requirement that each lane can be enabled/disabled
and configured individually.  Also it is potentially possible
that some of them are different due to calibration results.

> > +
> > +Example for Keystone K2E GBE:
> > +-----------------------------
> > +
> > +gbe_serdes0: gbe_serdes@232a000 {
> > +       #phy-cells              = <0>;
> > +       compatible              = "ti,keystone-serdes-gbe";
> > +       reg                     = <0x0232a000 0x2000>;
> > +       reg-names               = "serdes";
> > +       link-rate-kbps          = <1250000>;
> > +       num-lanes               = <4>;
> > +       lanes {
> > +               #address-cells = <1>;
> > +               #size-cells = <0>;
> > +               lane@0 {
> > +                       /*loopback;*/
> > +                       reg             = <0>;
> > +                       control-rate    = <2>; /* quart */
> > +                       rx-start        = <7 5>;
> > +                       rx-force        = <1 1>;
> > +                       tx-coeff        = <0 0 0 12 4>;
> > +                              /* c1 c2 cm att vreg */
> > +               };
> > +               lane@1 {
> > +                       /*loopback;*/
> > +                       reg             = <1>;
> > +                       control-rate    = <2>; /* quart */
> > +                       rx-start        = <7 5>;
> > +                       rx-force        = <1 1>;
> > +                       tx-coeff        = <0 0 0 12 4>;
> > +                              /* c1 c2 cm att vreg */
> > +               };
> > +       };
> > +};
> > +
> > +gbe_serdes1: gbe_serdes@2324000 {
> > +       #phy-cells              = <0>;
> > +       compatible              = "ti,keystone-serdes-gbe";
> > +       reg                     = <0x02324000 0x2000>;
> > +       reg-names               = "serdes";
> > +       link-rate-kbps          = <1250000>;
> > +       num-lanes               = <4>;
> 
> 4 lanes, but only 2 child nodes?
> 

since each lane can be enabled/disabled individually, a disabled
lane can have a node defined but with a status = "disabled" or
does not have a lane node defined at all.  this example shows the
latter.

> > +       lanes {
> > +               #address-cells = <1>;
> > +               #size-cells = <0>;
> > +               lane@0 {
> > +                       /*loopback;*/
> > +                       reg             = <0>;
> > +                       control-rate    = <2>; /* quart */
> > +                       rx-start        = <7 5>;
> > +                       rx-force        = <1 1>;
> > +                       tx-coeff        = <0 0 0 12 4>;
> > +                              /* c1 c2 cm att vreg */
> > +               };
> > +               lane@1 {
> > +                       /*loopback;*/
> > +                       reg             = <1>;
> > +                       control-rate    = <2>; /* quart */
> > +                       rx-start        = <7 5>;
> > +                       rx-force        = <1 1>;
> > +                       tx-coeff        = <0 0 0 12 4>;
> > +                              /* c1 c2 cm att vreg */
> > +               };
> > +       };
> > +};
> > +
> > +netcp: netcp@24000000 {
> > +       ...
> > +
> > +       netcp-devices {
> > +               ...
> > +
> > +               gbe@200000 { /* ETHSS */
> > +                       ...
> > +                       serdeses {
> > +                               #address-cells = <1>;
> > +                               #size-cells = <0>;
> > +                               serdes@0 {
> > +                                       reg = <0>;
> > +                                       phys = <&gbe_serdes0>;
> > +                                       status = "ok";
> > +                               };
> > +                               serdes@1 {
> > +                                       reg = <1>;
> > +                                       phys = <&gbe_serdes1>;
> > +                                       status = "ok";
> 
> This is way too complex. Just do:
> 
> phys = <&gbe_serdes0, &gbe_serdes1>;
> 
> in the gbe node.
> 

good point. will change to phys = <&gbe_serdes0>, <&gbe_serdes1>;

> Rob

Thanks,
WingMan

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 23:53       ` Kwok, WingMan
  0 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-15 23:53 UTC (permalink / raw
  To: linux-arm-kernel

Hello,

> -----Original Message-----
> From: Rob Herring [mailto:robh+dt at kernel.org]
> Sent: Thursday, October 15, 2015 12:15 PM
> To: Kwok, WingMan
> Cc: Pawel Moll; Mark Rutland; Ian Campbell; Kumar Gala; KISHON VIJAY ABRAHAM;
> Quadros, Roger; Karicheri, Muralidharan; Bjorn Helgaas; Santosh Shilimkar;
> Russell King - ARM Linux; devicetree at vger.kernel.org; linux-
> kernel at vger.kernel.org; linux-pci at vger.kernel.org; linux-arm-
> kernel at lists.infradead.org
> Subject: Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and
> pcie
> 
> On Thu, Oct 15, 2015 at 9:25 AM, WingMan Kwok <w-kwok2@ti.com> wrote:
> > On TI's Keystone platforms, several peripherals such as the
> > gbe ethernet switch, 10gbe ethernet switch and PCIe controller
> > require the use of a SerDes for converting SoC parallel data into
> > serialized data that can be output over a high-speed electrical
> > interface, and also converting high-speed serial input data
> > into parallel data that can be processed by the SoC.  The
> > SerDeses used by those peripherals, though they may be different,
> > are largely similar in functionality and setup.
> >
> > This patch provides a SerDes phy driver implementation that can be
> > used by the above mentioned peripheral drivers to configure their
> > respective SerDeses.
> >
> > v1:
> >         - see cover letter for review comments addressed.
> >
> > Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
> > ---
> >  Documentation/devicetree/bindings/phy/ti-phy.txt |  278 +++
> >  drivers/phy/Kconfig                              |    8 +
> >  drivers/phy/Makefile                             |    1 +
> >  drivers/phy/phy-keystone-serdes.c                | 2373
> ++++++++++++++++++++++
> >  4 files changed, 2660 insertions(+)
> >  create mode 100644 drivers/phy/phy-keystone-serdes.c
> >
> > diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt
> b/Documentation/devicetree/bindings/phy/ti-phy.txt
> > index 9cf9446..4dca271 100644
> > --- a/Documentation/devicetree/bindings/phy/ti-phy.txt
> > +++ b/Documentation/devicetree/bindings/phy/ti-phy.txt
> > @@ -115,4 +115,282 @@ sata_phy: phy at 4A096000 {
> >         clock-names = "sysclk", "refclk";
> >         syscon-pllreset = <&scm_conf 0x3fc>;
> >         #phy-cells = <0>;
> > +
> > +TI Keystone SerDes PHY
> > +======================
> > +
> > +Required properties:
> > + - compatible: should be one of
> > +       * "ti,keystone-serdes-gbe"
> > +       * "ti,keystone-serdes-xgbe"
> > +       * "ti,keystone-serdes-pcie"
> 
> These are different blocks or different modes of the same block? It's
> fine if the former. If the latter, then you should have a single
> compatible and then have a mode property. Perhaps phy-connection-type
> from ePAPR ethernet binding can be extended.
> 

these are different hw blocks configured specifically
for the corresponding peripheral.

> 
> > + - reg:
> > +       * base address and length of the SerDes register set
> > + - reg-names:
> > +       * "serdes"
> > +               - name of the reg SerDes register set
> 
> reg-names is kind of pointless with only 1.
> 

will remove.

> > + - #phy-cells:
> > +       * From the generic phy bindings, must be 0;
> > + - num-lanes:
> > +       * Number of lanes in SerDes.
> > +
> > +Optional properties:
> > + - syscon-peripheral:
> > +       * Handle to the subsystem register region of the peripheral
> > +         inside which the SerDes exists.
> > + - syscon-link:
> > +       * Handle to the Link register region of the peripheral inside
> > +         which the SerDes exists.  Example: it is the PCSR register
> > +         region in the case of 10gbe.
> > + - rx-force-enable:
> > +       * Include this property if receiver attenuation and boost are
> > +         to be configured with specific values defined in rx-force.
> > + - link-rate-kbps:
> > +       * SerDes link rate to be configured, in kbps.
> > +
> > +
> > +For gbe and 10gbe SerDes, it is optional to represent each lane as
> > +a sub-node, which can be enabled or disabled individually using
> > +the "status" property.
> > +
> > +Required properties (lane sub-node):
> > + - reg:
> > +       * lane number
> > +
> > +Optional properties (lane sub-node):
> > + - control-rate:
> > +       * Lane control rate
> > +               0: full rate
> > +               1: half rate
> > +               2: quarter rate
> > + - rx-start:
> > +       * Initial lane rx equalizer attenuation and boost configurations.
> > +       * Must be array of 2 integers.
> > + - rx-force:
> > +       * Forced lane rx equalizer attenuation and boost configurations.
> > +       * Must be array of 2 integers.
> > + - tx-coeff:
> > +       * Lane c1, c2, cm, attenuation and regulator output voltage
> > +         configurations.
> > +       * Must be array of 5 integers.
> > + - loopback:
> > +       * Include this property to enable loopback at the SerDes
> > +         lane level.
> 
> This seems overly complicated. Do you really expect these to be
> different per lane?
> 

It is an requirement that each lane can be enabled/disabled
and configured individually.  Also it is potentially possible
that some of them are different due to calibration results.

> > +
> > +Example for Keystone K2E GBE:
> > +-----------------------------
> > +
> > +gbe_serdes0: gbe_serdes at 232a000 {
> > +       #phy-cells              = <0>;
> > +       compatible              = "ti,keystone-serdes-gbe";
> > +       reg                     = <0x0232a000 0x2000>;
> > +       reg-names               = "serdes";
> > +       link-rate-kbps          = <1250000>;
> > +       num-lanes               = <4>;
> > +       lanes {
> > +               #address-cells = <1>;
> > +               #size-cells = <0>;
> > +               lane at 0 {
> > +                       /*loopback;*/
> > +                       reg             = <0>;
> > +                       control-rate    = <2>; /* quart */
> > +                       rx-start        = <7 5>;
> > +                       rx-force        = <1 1>;
> > +                       tx-coeff        = <0 0 0 12 4>;
> > +                              /* c1 c2 cm att vreg */
> > +               };
> > +               lane at 1 {
> > +                       /*loopback;*/
> > +                       reg             = <1>;
> > +                       control-rate    = <2>; /* quart */
> > +                       rx-start        = <7 5>;
> > +                       rx-force        = <1 1>;
> > +                       tx-coeff        = <0 0 0 12 4>;
> > +                              /* c1 c2 cm att vreg */
> > +               };
> > +       };
> > +};
> > +
> > +gbe_serdes1: gbe_serdes at 2324000 {
> > +       #phy-cells              = <0>;
> > +       compatible              = "ti,keystone-serdes-gbe";
> > +       reg                     = <0x02324000 0x2000>;
> > +       reg-names               = "serdes";
> > +       link-rate-kbps          = <1250000>;
> > +       num-lanes               = <4>;
> 
> 4 lanes, but only 2 child nodes?
> 

since each lane can be enabled/disabled individually, a disabled
lane can have a node defined but with a status = "disabled" or
does not have a lane node defined at all.  this example shows the
latter.

> > +       lanes {
> > +               #address-cells = <1>;
> > +               #size-cells = <0>;
> > +               lane at 0 {
> > +                       /*loopback;*/
> > +                       reg             = <0>;
> > +                       control-rate    = <2>; /* quart */
> > +                       rx-start        = <7 5>;
> > +                       rx-force        = <1 1>;
> > +                       tx-coeff        = <0 0 0 12 4>;
> > +                              /* c1 c2 cm att vreg */
> > +               };
> > +               lane at 1 {
> > +                       /*loopback;*/
> > +                       reg             = <1>;
> > +                       control-rate    = <2>; /* quart */
> > +                       rx-start        = <7 5>;
> > +                       rx-force        = <1 1>;
> > +                       tx-coeff        = <0 0 0 12 4>;
> > +                              /* c1 c2 cm att vreg */
> > +               };
> > +       };
> > +};
> > +
> > +netcp: netcp at 24000000 {
> > +       ...
> > +
> > +       netcp-devices {
> > +               ...
> > +
> > +               gbe at 200000 { /* ETHSS */
> > +                       ...
> > +                       serdeses {
> > +                               #address-cells = <1>;
> > +                               #size-cells = <0>;
> > +                               serdes at 0 {
> > +                                       reg = <0>;
> > +                                       phys = <&gbe_serdes0>;
> > +                                       status = "ok";
> > +                               };
> > +                               serdes at 1 {
> > +                                       reg = <1>;
> > +                                       phys = <&gbe_serdes1>;
> > +                                       status = "ok";
> 
> This is way too complex. Just do:
> 
> phys = <&gbe_serdes0, &gbe_serdes1>;
> 
> in the gbe node.
> 

good point. will change to phys = <&gbe_serdes0>, <&gbe_serdes1>;

> Rob

Thanks,
WingMan

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 23:53       ` Kwok, WingMan
  0 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-15 23:53 UTC (permalink / raw
  To: Rob Herring
  Cc: Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	KISHON VIJAY ABRAHAM, Quadros, Roger, Karicheri, Muralidharan,
	Bjorn Helgaas, Santosh Shilimkar, Russell King - ARM Linux,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org

SGVsbG8sDQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogUm9iIEhlcnJp
bmcgW21haWx0bzpyb2JoK2R0QGtlcm5lbC5vcmddDQo+IFNlbnQ6IFRodXJzZGF5LCBPY3RvYmVy
IDE1LCAyMDE1IDEyOjE1IFBNDQo+IFRvOiBLd29rLCBXaW5nTWFuDQo+IENjOiBQYXdlbCBNb2xs
OyBNYXJrIFJ1dGxhbmQ7IElhbiBDYW1wYmVsbDsgS3VtYXIgR2FsYTsgS0lTSE9OIFZJSkFZIEFC
UkFIQU07DQo+IFF1YWRyb3MsIFJvZ2VyOyBLYXJpY2hlcmksIE11cmFsaWRoYXJhbjsgQmpvcm4g
SGVsZ2FhczsgU2FudG9zaCBTaGlsaW1rYXI7DQo+IFJ1c3NlbGwgS2luZyAtIEFSTSBMaW51eDsg
ZGV2aWNldHJlZUB2Z2VyLmtlcm5lbC5vcmc7IGxpbnV4LQ0KPiBrZXJuZWxAdmdlci5rZXJuZWwu
b3JnOyBsaW51eC1wY2lAdmdlci5rZXJuZWwub3JnOyBsaW51eC1hcm0tDQo+IGtlcm5lbEBsaXN0
cy5pbmZyYWRlYWQub3JnDQo+IFN1YmplY3Q6IFJlOiBbUEFUQ0ggdjEgMS8yXSBwaHk6IGtleXN0
b25lOiBzZXJkZXMgZHJpdmVyIGZvciBnYmUgMTBnYmUgYW5kDQo+IHBjaWUNCj4gDQo+IE9uIFRo
dSwgT2N0IDE1LCAyMDE1IGF0IDk6MjUgQU0sIFdpbmdNYW4gS3dvayA8dy1rd29rMkB0aS5jb20+
IHdyb3RlOg0KPiA+IE9uIFRJJ3MgS2V5c3RvbmUgcGxhdGZvcm1zLCBzZXZlcmFsIHBlcmlwaGVy
YWxzIHN1Y2ggYXMgdGhlDQo+ID4gZ2JlIGV0aGVybmV0IHN3aXRjaCwgMTBnYmUgZXRoZXJuZXQg
c3dpdGNoIGFuZCBQQ0llIGNvbnRyb2xsZXINCj4gPiByZXF1aXJlIHRoZSB1c2Ugb2YgYSBTZXJE
ZXMgZm9yIGNvbnZlcnRpbmcgU29DIHBhcmFsbGVsIGRhdGEgaW50bw0KPiA+IHNlcmlhbGl6ZWQg
ZGF0YSB0aGF0IGNhbiBiZSBvdXRwdXQgb3ZlciBhIGhpZ2gtc3BlZWQgZWxlY3RyaWNhbA0KPiA+
IGludGVyZmFjZSwgYW5kIGFsc28gY29udmVydGluZyBoaWdoLXNwZWVkIHNlcmlhbCBpbnB1dCBk
YXRhDQo+ID4gaW50byBwYXJhbGxlbCBkYXRhIHRoYXQgY2FuIGJlIHByb2Nlc3NlZCBieSB0aGUg
U29DLiAgVGhlDQo+ID4gU2VyRGVzZXMgdXNlZCBieSB0aG9zZSBwZXJpcGhlcmFscywgdGhvdWdo
IHRoZXkgbWF5IGJlIGRpZmZlcmVudCwNCj4gPiBhcmUgbGFyZ2VseSBzaW1pbGFyIGluIGZ1bmN0
aW9uYWxpdHkgYW5kIHNldHVwLg0KPiA+DQo+ID4gVGhpcyBwYXRjaCBwcm92aWRlcyBhIFNlckRl
cyBwaHkgZHJpdmVyIGltcGxlbWVudGF0aW9uIHRoYXQgY2FuIGJlDQo+ID4gdXNlZCBieSB0aGUg
YWJvdmUgbWVudGlvbmVkIHBlcmlwaGVyYWwgZHJpdmVycyB0byBjb25maWd1cmUgdGhlaXINCj4g
PiByZXNwZWN0aXZlIFNlckRlc2VzLg0KPiA+DQo+ID4gdjE6DQo+ID4gICAgICAgICAtIHNlZSBj
b3ZlciBsZXR0ZXIgZm9yIHJldmlldyBjb21tZW50cyBhZGRyZXNzZWQuDQo+ID4NCj4gPiBTaWdu
ZWQtb2ZmLWJ5OiBXaW5nTWFuIEt3b2sgPHcta3dvazJAdGkuY29tPg0KPiA+IC0tLQ0KPiA+ICBE
b2N1bWVudGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3MvcGh5L3RpLXBoeS50eHQgfCAgMjc4ICsr
Kw0KPiA+ICBkcml2ZXJzL3BoeS9LY29uZmlnICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
fCAgICA4ICsNCj4gPiAgZHJpdmVycy9waHkvTWFrZWZpbGUgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgIHwgICAgMSArDQo+ID4gIGRyaXZlcnMvcGh5L3BoeS1rZXlzdG9uZS1zZXJkZXMuYyAg
ICAgICAgICAgICAgICB8IDIzNzMNCj4gKysrKysrKysrKysrKysrKysrKysrKw0KPiA+ICA0IGZp
bGVzIGNoYW5nZWQsIDI2NjAgaW5zZXJ0aW9ucygrKQ0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQg
ZHJpdmVycy9waHkvcGh5LWtleXN0b25lLXNlcmRlcy5jDQo+ID4NCj4gPiBkaWZmIC0tZ2l0IGEv
RG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdzL3BoeS90aS1waHkudHh0DQo+IGIvRG9j
dW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdzL3BoeS90aS1waHkudHh0DQo+ID4gaW5kZXgg
OWNmOTQ0Ni4uNGRjYTI3MSAxMDA2NDQNCj4gPiAtLS0gYS9Eb2N1bWVudGF0aW9uL2RldmljZXRy
ZWUvYmluZGluZ3MvcGh5L3RpLXBoeS50eHQNCj4gPiArKysgYi9Eb2N1bWVudGF0aW9uL2Rldmlj
ZXRyZWUvYmluZGluZ3MvcGh5L3RpLXBoeS50eHQNCj4gPiBAQCAtMTE1LDQgKzExNSwyODIgQEAg
c2F0YV9waHk6IHBoeUA0QTA5NjAwMCB7DQo+ID4gICAgICAgICBjbG9jay1uYW1lcyA9ICJzeXNj
bGsiLCAicmVmY2xrIjsNCj4gPiAgICAgICAgIHN5c2Nvbi1wbGxyZXNldCA9IDwmc2NtX2NvbmYg
MHgzZmM+Ow0KPiA+ICAgICAgICAgI3BoeS1jZWxscyA9IDwwPjsNCj4gPiArDQo+ID4gK1RJIEtl
eXN0b25lIFNlckRlcyBQSFkNCj4gPiArPT09PT09PT09PT09PT09PT09PT09PQ0KPiA+ICsNCj4g
PiArUmVxdWlyZWQgcHJvcGVydGllczoNCj4gPiArIC0gY29tcGF0aWJsZTogc2hvdWxkIGJlIG9u
ZSBvZg0KPiA+ICsgICAgICAgKiAidGksa2V5c3RvbmUtc2VyZGVzLWdiZSINCj4gPiArICAgICAg
ICogInRpLGtleXN0b25lLXNlcmRlcy14Z2JlIg0KPiA+ICsgICAgICAgKiAidGksa2V5c3RvbmUt
c2VyZGVzLXBjaWUiDQo+IA0KPiBUaGVzZSBhcmUgZGlmZmVyZW50IGJsb2NrcyBvciBkaWZmZXJl
bnQgbW9kZXMgb2YgdGhlIHNhbWUgYmxvY2s/IEl0J3MNCj4gZmluZSBpZiB0aGUgZm9ybWVyLiBJ
ZiB0aGUgbGF0dGVyLCB0aGVuIHlvdSBzaG91bGQgaGF2ZSBhIHNpbmdsZQ0KPiBjb21wYXRpYmxl
IGFuZCB0aGVuIGhhdmUgYSBtb2RlIHByb3BlcnR5LiBQZXJoYXBzIHBoeS1jb25uZWN0aW9uLXR5
cGUNCj4gZnJvbSBlUEFQUiBldGhlcm5ldCBiaW5kaW5nIGNhbiBiZSBleHRlbmRlZC4NCj4gDQoN
CnRoZXNlIGFyZSBkaWZmZXJlbnQgaHcgYmxvY2tzIGNvbmZpZ3VyZWQgc3BlY2lmaWNhbGx5DQpm
b3IgdGhlIGNvcnJlc3BvbmRpbmcgcGVyaXBoZXJhbC4NCg0KPiANCj4gPiArIC0gcmVnOg0KPiA+
ICsgICAgICAgKiBiYXNlIGFkZHJlc3MgYW5kIGxlbmd0aCBvZiB0aGUgU2VyRGVzIHJlZ2lzdGVy
IHNldA0KPiA+ICsgLSByZWctbmFtZXM6DQo+ID4gKyAgICAgICAqICJzZXJkZXMiDQo+ID4gKyAg
ICAgICAgICAgICAgIC0gbmFtZSBvZiB0aGUgcmVnIFNlckRlcyByZWdpc3RlciBzZXQNCj4gDQo+
IHJlZy1uYW1lcyBpcyBraW5kIG9mIHBvaW50bGVzcyB3aXRoIG9ubHkgMS4NCj4gDQoNCndpbGwg
cmVtb3ZlLg0KDQo+ID4gKyAtICNwaHktY2VsbHM6DQo+ID4gKyAgICAgICAqIEZyb20gdGhlIGdl
bmVyaWMgcGh5IGJpbmRpbmdzLCBtdXN0IGJlIDA7DQo+ID4gKyAtIG51bS1sYW5lczoNCj4gPiAr
ICAgICAgICogTnVtYmVyIG9mIGxhbmVzIGluIFNlckRlcy4NCj4gPiArDQo+ID4gK09wdGlvbmFs
IHByb3BlcnRpZXM6DQo+ID4gKyAtIHN5c2Nvbi1wZXJpcGhlcmFsOg0KPiA+ICsgICAgICAgKiBI
YW5kbGUgdG8gdGhlIHN1YnN5c3RlbSByZWdpc3RlciByZWdpb24gb2YgdGhlIHBlcmlwaGVyYWwN
Cj4gPiArICAgICAgICAgaW5zaWRlIHdoaWNoIHRoZSBTZXJEZXMgZXhpc3RzLg0KPiA+ICsgLSBz
eXNjb24tbGluazoNCj4gPiArICAgICAgICogSGFuZGxlIHRvIHRoZSBMaW5rIHJlZ2lzdGVyIHJl
Z2lvbiBvZiB0aGUgcGVyaXBoZXJhbCBpbnNpZGUNCj4gPiArICAgICAgICAgd2hpY2ggdGhlIFNl
ckRlcyBleGlzdHMuICBFeGFtcGxlOiBpdCBpcyB0aGUgUENTUiByZWdpc3Rlcg0KPiA+ICsgICAg
ICAgICByZWdpb24gaW4gdGhlIGNhc2Ugb2YgMTBnYmUuDQo+ID4gKyAtIHJ4LWZvcmNlLWVuYWJs
ZToNCj4gPiArICAgICAgICogSW5jbHVkZSB0aGlzIHByb3BlcnR5IGlmIHJlY2VpdmVyIGF0dGVu
dWF0aW9uIGFuZCBib29zdCBhcmUNCj4gPiArICAgICAgICAgdG8gYmUgY29uZmlndXJlZCB3aXRo
IHNwZWNpZmljIHZhbHVlcyBkZWZpbmVkIGluIHJ4LWZvcmNlLg0KPiA+ICsgLSBsaW5rLXJhdGUt
a2JwczoNCj4gPiArICAgICAgICogU2VyRGVzIGxpbmsgcmF0ZSB0byBiZSBjb25maWd1cmVkLCBp
biBrYnBzLg0KPiA+ICsNCj4gPiArDQo+ID4gK0ZvciBnYmUgYW5kIDEwZ2JlIFNlckRlcywgaXQg
aXMgb3B0aW9uYWwgdG8gcmVwcmVzZW50IGVhY2ggbGFuZSBhcw0KPiA+ICthIHN1Yi1ub2RlLCB3
aGljaCBjYW4gYmUgZW5hYmxlZCBvciBkaXNhYmxlZCBpbmRpdmlkdWFsbHkgdXNpbmcNCj4gPiAr
dGhlICJzdGF0dXMiIHByb3BlcnR5Lg0KPiA+ICsNCj4gPiArUmVxdWlyZWQgcHJvcGVydGllcyAo
bGFuZSBzdWItbm9kZSk6DQo+ID4gKyAtIHJlZzoNCj4gPiArICAgICAgICogbGFuZSBudW1iZXIN
Cj4gPiArDQo+ID4gK09wdGlvbmFsIHByb3BlcnRpZXMgKGxhbmUgc3ViLW5vZGUpOg0KPiA+ICsg
LSBjb250cm9sLXJhdGU6DQo+ID4gKyAgICAgICAqIExhbmUgY29udHJvbCByYXRlDQo+ID4gKyAg
ICAgICAgICAgICAgIDA6IGZ1bGwgcmF0ZQ0KPiA+ICsgICAgICAgICAgICAgICAxOiBoYWxmIHJh
dGUNCj4gPiArICAgICAgICAgICAgICAgMjogcXVhcnRlciByYXRlDQo+ID4gKyAtIHJ4LXN0YXJ0
Og0KPiA+ICsgICAgICAgKiBJbml0aWFsIGxhbmUgcnggZXF1YWxpemVyIGF0dGVudWF0aW9uIGFu
ZCBib29zdCBjb25maWd1cmF0aW9ucy4NCj4gPiArICAgICAgICogTXVzdCBiZSBhcnJheSBvZiAy
IGludGVnZXJzLg0KPiA+ICsgLSByeC1mb3JjZToNCj4gPiArICAgICAgICogRm9yY2VkIGxhbmUg
cnggZXF1YWxpemVyIGF0dGVudWF0aW9uIGFuZCBib29zdCBjb25maWd1cmF0aW9ucy4NCj4gPiAr
ICAgICAgICogTXVzdCBiZSBhcnJheSBvZiAyIGludGVnZXJzLg0KPiA+ICsgLSB0eC1jb2VmZjoN
Cj4gPiArICAgICAgICogTGFuZSBjMSwgYzIsIGNtLCBhdHRlbnVhdGlvbiBhbmQgcmVndWxhdG9y
IG91dHB1dCB2b2x0YWdlDQo+ID4gKyAgICAgICAgIGNvbmZpZ3VyYXRpb25zLg0KPiA+ICsgICAg
ICAgKiBNdXN0IGJlIGFycmF5IG9mIDUgaW50ZWdlcnMuDQo+ID4gKyAtIGxvb3BiYWNrOg0KPiA+
ICsgICAgICAgKiBJbmNsdWRlIHRoaXMgcHJvcGVydHkgdG8gZW5hYmxlIGxvb3BiYWNrIGF0IHRo
ZSBTZXJEZXMNCj4gPiArICAgICAgICAgbGFuZSBsZXZlbC4NCj4gDQo+IFRoaXMgc2VlbXMgb3Zl
cmx5IGNvbXBsaWNhdGVkLiBEbyB5b3UgcmVhbGx5IGV4cGVjdCB0aGVzZSB0byBiZQ0KPiBkaWZm
ZXJlbnQgcGVyIGxhbmU/DQo+IA0KDQpJdCBpcyBhbiByZXF1aXJlbWVudCB0aGF0IGVhY2ggbGFu
ZSBjYW4gYmUgZW5hYmxlZC9kaXNhYmxlZA0KYW5kIGNvbmZpZ3VyZWQgaW5kaXZpZHVhbGx5LiAg
QWxzbyBpdCBpcyBwb3RlbnRpYWxseSBwb3NzaWJsZQ0KdGhhdCBzb21lIG9mIHRoZW0gYXJlIGRp
ZmZlcmVudCBkdWUgdG8gY2FsaWJyYXRpb24gcmVzdWx0cy4NCg0KPiA+ICsNCj4gPiArRXhhbXBs
ZSBmb3IgS2V5c3RvbmUgSzJFIEdCRToNCj4gPiArLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0NCj4gPiArDQo+ID4gK2diZV9zZXJkZXMwOiBnYmVfc2VyZGVzQDIzMmEwMDAgew0KPiA+ICsg
ICAgICAgI3BoeS1jZWxscyAgICAgICAgICAgICAgPSA8MD47DQo+ID4gKyAgICAgICBjb21wYXRp
YmxlICAgICAgICAgICAgICA9ICJ0aSxrZXlzdG9uZS1zZXJkZXMtZ2JlIjsNCj4gPiArICAgICAg
IHJlZyAgICAgICAgICAgICAgICAgICAgID0gPDB4MDIzMmEwMDAgMHgyMDAwPjsNCj4gPiArICAg
ICAgIHJlZy1uYW1lcyAgICAgICAgICAgICAgID0gInNlcmRlcyI7DQo+ID4gKyAgICAgICBsaW5r
LXJhdGUta2JwcyAgICAgICAgICA9IDwxMjUwMDAwPjsNCj4gPiArICAgICAgIG51bS1sYW5lcyAg
ICAgICAgICAgICAgID0gPDQ+Ow0KPiA+ICsgICAgICAgbGFuZXMgew0KPiA+ICsgICAgICAgICAg
ICAgICAjYWRkcmVzcy1jZWxscyA9IDwxPjsNCj4gPiArICAgICAgICAgICAgICAgI3NpemUtY2Vs
bHMgPSA8MD47DQo+ID4gKyAgICAgICAgICAgICAgIGxhbmVAMCB7DQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgLypsb29wYmFjazsqLw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJl
ZyAgICAgICAgICAgICA9IDwwPjsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBjb250cm9s
LXJhdGUgICAgPSA8Mj47IC8qIHF1YXJ0ICovDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
cngtc3RhcnQgICAgICAgID0gPDcgNT47DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcngt
Zm9yY2UgICAgICAgID0gPDEgMT47DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgdHgtY29l
ZmYgICAgICAgID0gPDAgMCAwIDEyIDQ+Ow0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAvKiBjMSBjMiBjbSBhdHQgdnJlZyAqLw0KPiA+ICsgICAgICAgICAgICAgICB9Ow0KPiA+
ICsgICAgICAgICAgICAgICBsYW5lQDEgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIC8q
bG9vcGJhY2s7Ki8NCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZWcgICAgICAgICAgICAg
PSA8MT47DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbC1yYXRlICAgID0gPDI+
OyAvKiBxdWFydCAqLw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJ4LXN0YXJ0ICAgICAg
ICA9IDw3IDU+Ow0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJ4LWZvcmNlICAgICAgICA9
IDwxIDE+Ow0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHR4LWNvZWZmICAgICAgICA9IDww
IDAgMCAxMiA0PjsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLyogYzEgYzIg
Y20gYXR0IHZyZWcgKi8NCj4gPiArICAgICAgICAgICAgICAgfTsNCj4gPiArICAgICAgIH07DQo+
ID4gK307DQo+ID4gKw0KPiA+ICtnYmVfc2VyZGVzMTogZ2JlX3NlcmRlc0AyMzI0MDAwIHsNCj4g
PiArICAgICAgICNwaHktY2VsbHMgICAgICAgICAgICAgID0gPDA+Ow0KPiA+ICsgICAgICAgY29t
cGF0aWJsZSAgICAgICAgICAgICAgPSAidGksa2V5c3RvbmUtc2VyZGVzLWdiZSI7DQo+ID4gKyAg
ICAgICByZWcgICAgICAgICAgICAgICAgICAgICA9IDwweDAyMzI0MDAwIDB4MjAwMD47DQo+ID4g
KyAgICAgICByZWctbmFtZXMgICAgICAgICAgICAgICA9ICJzZXJkZXMiOw0KPiA+ICsgICAgICAg
bGluay1yYXRlLWticHMgICAgICAgICAgPSA8MTI1MDAwMD47DQo+ID4gKyAgICAgICBudW0tbGFu
ZXMgICAgICAgICAgICAgICA9IDw0PjsNCj4gDQo+IDQgbGFuZXMsIGJ1dCBvbmx5IDIgY2hpbGQg
bm9kZXM/DQo+IA0KDQpzaW5jZSBlYWNoIGxhbmUgY2FuIGJlIGVuYWJsZWQvZGlzYWJsZWQgaW5k
aXZpZHVhbGx5LCBhIGRpc2FibGVkDQpsYW5lIGNhbiBoYXZlIGEgbm9kZSBkZWZpbmVkIGJ1dCB3
aXRoIGEgc3RhdHVzID0gImRpc2FibGVkIiBvcg0KZG9lcyBub3QgaGF2ZSBhIGxhbmUgbm9kZSBk
ZWZpbmVkIGF0IGFsbC4gIHRoaXMgZXhhbXBsZSBzaG93cyB0aGUNCmxhdHRlci4NCg0KPiA+ICsg
ICAgICAgbGFuZXMgew0KPiA+ICsgICAgICAgICAgICAgICAjYWRkcmVzcy1jZWxscyA9IDwxPjsN
Cj4gPiArICAgICAgICAgICAgICAgI3NpemUtY2VsbHMgPSA8MD47DQo+ID4gKyAgICAgICAgICAg
ICAgIGxhbmVAMCB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgLypsb29wYmFjazsqLw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJlZyAgICAgICAgICAgICA9IDwwPjsNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sLXJhdGUgICAgPSA8Mj47IC8qIHF1YXJ0ICov
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcngtc3RhcnQgICAgICAgID0gPDcgNT47DQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcngtZm9yY2UgICAgICAgID0gPDEgMT47DQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgdHgtY29lZmYgICAgICAgID0gPDAgMCAwIDEyIDQ+Ow0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvKiBjMSBjMiBjbSBhdHQgdnJlZyAq
Lw0KPiA+ICsgICAgICAgICAgICAgICB9Ow0KPiA+ICsgICAgICAgICAgICAgICBsYW5lQDEgew0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIC8qbG9vcGJhY2s7Ki8NCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICByZWcgICAgICAgICAgICAgPSA8MT47DQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgY29udHJvbC1yYXRlICAgID0gPDI+OyAvKiBxdWFydCAqLw0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgIHJ4LXN0YXJ0ICAgICAgICA9IDw3IDU+Ow0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgIHJ4LWZvcmNlICAgICAgICA9IDwxIDE+Ow0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgIHR4LWNvZWZmICAgICAgICA9IDwwIDAgMCAxMiA0PjsNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgLyogYzEgYzIgY20gYXR0IHZyZWcgKi8NCj4gPiArICAgICAg
ICAgICAgICAgfTsNCj4gPiArICAgICAgIH07DQo+ID4gK307DQo+ID4gKw0KPiA+ICtuZXRjcDog
bmV0Y3BAMjQwMDAwMDAgew0KPiA+ICsgICAgICAgLi4uDQo+ID4gKw0KPiA+ICsgICAgICAgbmV0
Y3AtZGV2aWNlcyB7DQo+ID4gKyAgICAgICAgICAgICAgIC4uLg0KPiA+ICsNCj4gPiArICAgICAg
ICAgICAgICAgZ2JlQDIwMDAwMCB7IC8qIEVUSFNTICovDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgLi4uDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgc2VyZGVzZXMgew0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2FkZHJlc3MtY2VsbHMgPSA8MT47DQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjc2l6ZS1jZWxscyA9IDwwPjsNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmRlc0AwIHsNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnID0gPDA+Ow0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwaHlzID0gPCZnYmVfc2VyZGVzMD47DQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXR1cyA9ICJvayI7DQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9Ow0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgc2VyZGVzQDEgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICByZWcgPSA8MT47DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIHBoeXMgPSA8JmdiZV9zZXJkZXMxPjsNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzID0gIm9rIjsNCj4gDQo+IFRoaXMgaXMg
d2F5IHRvbyBjb21wbGV4LiBKdXN0IGRvOg0KPiANCj4gcGh5cyA9IDwmZ2JlX3NlcmRlczAsICZn
YmVfc2VyZGVzMT47DQo+IA0KPiBpbiB0aGUgZ2JlIG5vZGUuDQo+IA0KDQpnb29kIHBvaW50LiB3
aWxsIGNoYW5nZSB0byBwaHlzID0gPCZnYmVfc2VyZGVzMD4sIDwmZ2JlX3NlcmRlczE+Ow0KDQo+
IFJvYg0KDQpUaGFua3MsDQpXaW5nTWFuDQo=

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-15 20:53         ` Arnd Bergmann
  (?)
  (?)
@ 2015-10-15 23:57           ` Kwok, WingMan
  -1 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-15 23:57 UTC (permalink / raw
  To: Arnd Bergmann
  Cc: linux-arm-kernel@lists.infradead.org, robh+dt@kernel.org,
	pawel.moll@arm.com, mark.rutland@arm.com,
	ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
	KISHON VIJAY ABRAHAM, Quadros, Roger, Karicheri, Muralidharan,
	bhelgaas@google.com, ssantosh@kernel.org, linux@arm.linux.org.uk,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 3874 bytes --]

Hello,

> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd@arndb.de]
> Sent: Thursday, October 15, 2015 4:53 PM
> To: Kwok, WingMan
> Cc: linux-arm-kernel@lists.infradead.org; robh+dt@kernel.org;
> pawel.moll@arm.com; mark.rutland@arm.com; ijc+devicetree@hellion.org.uk;
> galak@codeaurora.org; KISHON VIJAY ABRAHAM; Quadros, Roger; Karicheri,
> Muralidharan; bhelgaas@google.com; ssantosh@kernel.org;
> linux@arm.linux.org.uk; devicetree@vger.kernel.org; linux-
> kernel@vger.kernel.org; linux-pci@vger.kernel.org
> Subject: Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and
> pcie
> 
> On Thursday 15 October 2015 20:08:32 Kwok, WingMan wrote:
> >
> > > > +#define reg_rmw(addr, value, mask) \
> > > > +   __raw_writel(((__raw_readl(addr) & (~(mask))) | \
> > > > +                   (value & (mask))), (addr))
> > >
> > > not endian safe, and potentially racy.
> > >
> >
> > will change to
> >
> > #define reg_rmw(addr, value, mask) \
> >         writel(((readl(addr) & (~(mask))) | \
> >                         (value & (mask))), (addr))
> 
> Ok, sounds good. Note that if any of this is performance critical,
> better use readl_relaxed(), but as long as this is just for setup
> code and not for data transfers, staying with readl() as you
> suggest is better.
> 

since this is only for initialization, I'll probably stay with readl().

> > > > +static inline void _kserdes_reset_cdr(void __iomem *sregs, int lane)
> > > > +{
> > > > +   /* toggle signal detect */
> > > > +   _kserdes_force_signal_detect_low(sregs, lane);
> > > > +   mdelay(1);
> > > > +   _kserdes_force_signal_detect_high(sregs, lane);
> > > > +}
> > >
> > > Can you change the code so you can use msleep(1) here?
> > >
> >
> > will replace delays with usleep_range()
> 
> Ok.
> 
> > > > +
> > > > +   do {
> > > > +           mdelay(10);
> > > > +           memset(lane_down, 0, sizeof(lane_down));
> > > > +
> > > > +           link_up = _kserdes_check_link_status(dev, sregs,
> > > > +                                                pcsr_regmap, lanes,
> > > > +                                                lanes_enable,
> > > > +                                                current_state,
> lane_down);
> > > > +
> > > > +           /* if we did not get link up then wait 100ms
> > > > +            * before calling it again
> > > > +            */
> > > > +           if (link_up)
> > > > +                   break;
> > > > +
> > > > +           for (i = 0; i < lanes; i++) {
> > > > +                   if ((lanes_enable & (1 << i)) && lane_down[i])
> > > > +                           dev_dbg(dev,
> > > > +                                   "XGE: detected lane down on lane
> %d\n",
> > > > +                                   i);
> > > > +           }
> > > > +
> > > > +           if (++retries > 100)
> > > > +                   return -ETIMEDOUT;
> > > > +
> > > > +   } while (!link_up);
> > >
> > > an more importantly here. Blocking the CPU for over one second is not
> good.
> > >
> > > Any use of mdelay() should have a comment explaining why you cannot use
> > > msleep() in that instance.
> > >
> >
> > will replace delays with usleep_range()
> 
> Here you have to be careful with the total runtime. Using usleep_range()
> is a good idea, and you can have a particularly wide range, but then you
> should changen the timeout condition from number of retries to total
> elapsed time like
> 
> 	unsigned long timeout = jiffies + HZ; /* 1 second maximum */
> 	do {
> 		...
> 
> 		if (link_up)
> 			break;
> 
> 		if (time_after(jiffies, timeout)
> 			return -ETIMEOUT;
> 
> 		usleep_range(1000, 50000);
> 	} while (1);
> 

will do.  

> 	Arnd

Thanks so much for your comments.
WingMan
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 23:57           ` Kwok, WingMan
  0 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-15 23:57 UTC (permalink / raw
  To: Arnd Bergmann
  Cc: linux-arm-kernel@lists.infradead.org, robh+dt@kernel.org,
	pawel.moll@arm.com, mark.rutland@arm.com,
	ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
	KISHON VIJAY ABRAHAM, Quadros, Roger, Karicheri, Muralidharan,
	bhelgaas@google.com, ssantosh@kernel.org, linux@arm.linux.org.uk,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org

Hello,

> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd@arndb.de]
> Sent: Thursday, October 15, 2015 4:53 PM
> To: Kwok, WingMan
> Cc: linux-arm-kernel@lists.infradead.org; robh+dt@kernel.org;
> pawel.moll@arm.com; mark.rutland@arm.com; ijc+devicetree@hellion.org.uk;
> galak@codeaurora.org; KISHON VIJAY ABRAHAM; Quadros, Roger; Karicheri,
> Muralidharan; bhelgaas@google.com; ssantosh@kernel.org;
> linux@arm.linux.org.uk; devicetree@vger.kernel.org; linux-
> kernel@vger.kernel.org; linux-pci@vger.kernel.org
> Subject: Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and
> pcie
> 
> On Thursday 15 October 2015 20:08:32 Kwok, WingMan wrote:
> >
> > > > +#define reg_rmw(addr, value, mask) \
> > > > +   __raw_writel(((__raw_readl(addr) & (~(mask))) | \
> > > > +                   (value & (mask))), (addr))
> > >
> > > not endian safe, and potentially racy.
> > >
> >
> > will change to
> >
> > #define reg_rmw(addr, value, mask) \
> >         writel(((readl(addr) & (~(mask))) | \
> >                         (value & (mask))), (addr))
> 
> Ok, sounds good. Note that if any of this is performance critical,
> better use readl_relaxed(), but as long as this is just for setup
> code and not for data transfers, staying with readl() as you
> suggest is better.
> 

since this is only for initialization, I'll probably stay with readl().

> > > > +static inline void _kserdes_reset_cdr(void __iomem *sregs, int lane)
> > > > +{
> > > > +   /* toggle signal detect */
> > > > +   _kserdes_force_signal_detect_low(sregs, lane);
> > > > +   mdelay(1);
> > > > +   _kserdes_force_signal_detect_high(sregs, lane);
> > > > +}
> > >
> > > Can you change the code so you can use msleep(1) here?
> > >
> >
> > will replace delays with usleep_range()
> 
> Ok.
> 
> > > > +
> > > > +   do {
> > > > +           mdelay(10);
> > > > +           memset(lane_down, 0, sizeof(lane_down));
> > > > +
> > > > +           link_up = _kserdes_check_link_status(dev, sregs,
> > > > +                                                pcsr_regmap, lanes,
> > > > +                                                lanes_enable,
> > > > +                                                current_state,
> lane_down);
> > > > +
> > > > +           /* if we did not get link up then wait 100ms
> > > > +            * before calling it again
> > > > +            */
> > > > +           if (link_up)
> > > > +                   break;
> > > > +
> > > > +           for (i = 0; i < lanes; i++) {
> > > > +                   if ((lanes_enable & (1 << i)) && lane_down[i])
> > > > +                           dev_dbg(dev,
> > > > +                                   "XGE: detected lane down on lane
> %d\n",
> > > > +                                   i);
> > > > +           }
> > > > +
> > > > +           if (++retries > 100)
> > > > +                   return -ETIMEDOUT;
> > > > +
> > > > +   } while (!link_up);
> > >
> > > an more importantly here. Blocking the CPU for over one second is not
> good.
> > >
> > > Any use of mdelay() should have a comment explaining why you cannot use
> > > msleep() in that instance.
> > >
> >
> > will replace delays with usleep_range()
> 
> Here you have to be careful with the total runtime. Using usleep_range()
> is a good idea, and you can have a particularly wide range, but then you
> should changen the timeout condition from number of retries to total
> elapsed time like
> 
> 	unsigned long timeout = jiffies + HZ; /* 1 second maximum */
> 	do {
> 		...
> 
> 		if (link_up)
> 			break;
> 
> 		if (time_after(jiffies, timeout)
> 			return -ETIMEOUT;
> 
> 		usleep_range(1000, 50000);
> 	} while (1);
> 

will do.  

> 	Arnd

Thanks so much for your comments.
WingMan

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 23:57           ` Kwok, WingMan
  0 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-15 23:57 UTC (permalink / raw
  To: linux-arm-kernel

Hello,

> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd at arndb.de]
> Sent: Thursday, October 15, 2015 4:53 PM
> To: Kwok, WingMan
> Cc: linux-arm-kernel at lists.infradead.org; robh+dt at kernel.org;
> pawel.moll at arm.com; mark.rutland at arm.com; ijc+devicetree at hellion.org.uk;
> galak at codeaurora.org; KISHON VIJAY ABRAHAM; Quadros, Roger; Karicheri,
> Muralidharan; bhelgaas at google.com; ssantosh at kernel.org;
> linux at arm.linux.org.uk; devicetree at vger.kernel.org; linux-
> kernel at vger.kernel.org; linux-pci at vger.kernel.org
> Subject: Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and
> pcie
> 
> On Thursday 15 October 2015 20:08:32 Kwok, WingMan wrote:
> >
> > > > +#define reg_rmw(addr, value, mask) \
> > > > +   __raw_writel(((__raw_readl(addr) & (~(mask))) | \
> > > > +                   (value & (mask))), (addr))
> > >
> > > not endian safe, and potentially racy.
> > >
> >
> > will change to
> >
> > #define reg_rmw(addr, value, mask) \
> >         writel(((readl(addr) & (~(mask))) | \
> >                         (value & (mask))), (addr))
> 
> Ok, sounds good. Note that if any of this is performance critical,
> better use readl_relaxed(), but as long as this is just for setup
> code and not for data transfers, staying with readl() as you
> suggest is better.
> 

since this is only for initialization, I'll probably stay with readl().

> > > > +static inline void _kserdes_reset_cdr(void __iomem *sregs, int lane)
> > > > +{
> > > > +   /* toggle signal detect */
> > > > +   _kserdes_force_signal_detect_low(sregs, lane);
> > > > +   mdelay(1);
> > > > +   _kserdes_force_signal_detect_high(sregs, lane);
> > > > +}
> > >
> > > Can you change the code so you can use msleep(1) here?
> > >
> >
> > will replace delays with usleep_range()
> 
> Ok.
> 
> > > > +
> > > > +   do {
> > > > +           mdelay(10);
> > > > +           memset(lane_down, 0, sizeof(lane_down));
> > > > +
> > > > +           link_up = _kserdes_check_link_status(dev, sregs,
> > > > +                                                pcsr_regmap, lanes,
> > > > +                                                lanes_enable,
> > > > +                                                current_state,
> lane_down);
> > > > +
> > > > +           /* if we did not get link up then wait 100ms
> > > > +            * before calling it again
> > > > +            */
> > > > +           if (link_up)
> > > > +                   break;
> > > > +
> > > > +           for (i = 0; i < lanes; i++) {
> > > > +                   if ((lanes_enable & (1 << i)) && lane_down[i])
> > > > +                           dev_dbg(dev,
> > > > +                                   "XGE: detected lane down on lane
> %d\n",
> > > > +                                   i);
> > > > +           }
> > > > +
> > > > +           if (++retries > 100)
> > > > +                   return -ETIMEDOUT;
> > > > +
> > > > +   } while (!link_up);
> > >
> > > an more importantly here. Blocking the CPU for over one second is not
> good.
> > >
> > > Any use of mdelay() should have a comment explaining why you cannot use
> > > msleep() in that instance.
> > >
> >
> > will replace delays with usleep_range()
> 
> Here you have to be careful with the total runtime. Using usleep_range()
> is a good idea, and you can have a particularly wide range, but then you
> should changen the timeout condition from number of retries to total
> elapsed time like
> 
> 	unsigned long timeout = jiffies + HZ; /* 1 second maximum */
> 	do {
> 		...
> 
> 		if (link_up)
> 			break;
> 
> 		if (time_after(jiffies, timeout)
> 			return -ETIMEOUT;
> 
> 		usleep_range(1000, 50000);
> 	} while (1);
> 

will do.  

> 	Arnd

Thanks so much for your comments.
WingMan

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-15 23:57           ` Kwok, WingMan
  0 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-15 23:57 UTC (permalink / raw
  To: Arnd Bergmann
  Cc: linux-arm-kernel@lists.infradead.org, robh+dt@kernel.org,
	pawel.moll@arm.com, mark.rutland@arm.com,
	ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
	KISHON VIJAY ABRAHAM, Quadros, Roger, Karicheri, Muralidharan,
	bhelgaas@google.com, ssantosh@kernel.org, linux@arm.linux.org.uk,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org

SGVsbG8sDQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogQXJuZCBCZXJn
bWFubiBbbWFpbHRvOmFybmRAYXJuZGIuZGVdDQo+IFNlbnQ6IFRodXJzZGF5LCBPY3RvYmVyIDE1
LCAyMDE1IDQ6NTMgUE0NCj4gVG86IEt3b2ssIFdpbmdNYW4NCj4gQ2M6IGxpbnV4LWFybS1rZXJu
ZWxAbGlzdHMuaW5mcmFkZWFkLm9yZzsgcm9iaCtkdEBrZXJuZWwub3JnOw0KPiBwYXdlbC5tb2xs
QGFybS5jb207IG1hcmsucnV0bGFuZEBhcm0uY29tOyBpamMrZGV2aWNldHJlZUBoZWxsaW9uLm9y
Zy51azsNCj4gZ2FsYWtAY29kZWF1cm9yYS5vcmc7IEtJU0hPTiBWSUpBWSBBQlJBSEFNOyBRdWFk
cm9zLCBSb2dlcjsgS2FyaWNoZXJpLA0KPiBNdXJhbGlkaGFyYW47IGJoZWxnYWFzQGdvb2dsZS5j
b207IHNzYW50b3NoQGtlcm5lbC5vcmc7DQo+IGxpbnV4QGFybS5saW51eC5vcmcudWs7IGRldmlj
ZXRyZWVAdmdlci5rZXJuZWwub3JnOyBsaW51eC0NCj4ga2VybmVsQHZnZXIua2VybmVsLm9yZzsg
bGludXgtcGNpQHZnZXIua2VybmVsLm9yZw0KPiBTdWJqZWN0OiBSZTogW1BBVENIIHYxIDEvMl0g
cGh5OiBrZXlzdG9uZTogc2VyZGVzIGRyaXZlciBmb3IgZ2JlIDEwZ2JlIGFuZA0KPiBwY2llDQo+
IA0KPiBPbiBUaHVyc2RheSAxNSBPY3RvYmVyIDIwMTUgMjA6MDg6MzIgS3dvaywgV2luZ01hbiB3
cm90ZToNCj4gPg0KPiA+ID4gPiArI2RlZmluZSByZWdfcm13KGFkZHIsIHZhbHVlLCBtYXNrKSBc
DQo+ID4gPiA+ICsgICBfX3Jhd193cml0ZWwoKChfX3Jhd19yZWFkbChhZGRyKSAmICh+KG1hc2sp
KSkgfCBcDQo+ID4gPiA+ICsgICAgICAgICAgICAgICAgICAgKHZhbHVlICYgKG1hc2spKSksIChh
ZGRyKSkNCj4gPiA+DQo+ID4gPiBub3QgZW5kaWFuIHNhZmUsIGFuZCBwb3RlbnRpYWxseSByYWN5
Lg0KPiA+ID4NCj4gPg0KPiA+IHdpbGwgY2hhbmdlIHRvDQo+ID4NCj4gPiAjZGVmaW5lIHJlZ19y
bXcoYWRkciwgdmFsdWUsIG1hc2spIFwNCj4gPiAgICAgICAgIHdyaXRlbCgoKHJlYWRsKGFkZHIp
ICYgKH4obWFzaykpKSB8IFwNCj4gPiAgICAgICAgICAgICAgICAgICAgICAgICAodmFsdWUgJiAo
bWFzaykpKSwgKGFkZHIpKQ0KPiANCj4gT2ssIHNvdW5kcyBnb29kLiBOb3RlIHRoYXQgaWYgYW55
IG9mIHRoaXMgaXMgcGVyZm9ybWFuY2UgY3JpdGljYWwsDQo+IGJldHRlciB1c2UgcmVhZGxfcmVs
YXhlZCgpLCBidXQgYXMgbG9uZyBhcyB0aGlzIGlzIGp1c3QgZm9yIHNldHVwDQo+IGNvZGUgYW5k
IG5vdCBmb3IgZGF0YSB0cmFuc2ZlcnMsIHN0YXlpbmcgd2l0aCByZWFkbCgpIGFzIHlvdQ0KPiBz
dWdnZXN0IGlzIGJldHRlci4NCj4gDQoNCnNpbmNlIHRoaXMgaXMgb25seSBmb3IgaW5pdGlhbGl6
YXRpb24sIEknbGwgcHJvYmFibHkgc3RheSB3aXRoIHJlYWRsKCkuDQoNCj4gPiA+ID4gK3N0YXRp
YyBpbmxpbmUgdm9pZCBfa3NlcmRlc19yZXNldF9jZHIodm9pZCBfX2lvbWVtICpzcmVncywgaW50
IGxhbmUpDQo+ID4gPiA+ICt7DQo+ID4gPiA+ICsgICAvKiB0b2dnbGUgc2lnbmFsIGRldGVjdCAq
Lw0KPiA+ID4gPiArICAgX2tzZXJkZXNfZm9yY2Vfc2lnbmFsX2RldGVjdF9sb3coc3JlZ3MsIGxh
bmUpOw0KPiA+ID4gPiArICAgbWRlbGF5KDEpOw0KPiA+ID4gPiArICAgX2tzZXJkZXNfZm9yY2Vf
c2lnbmFsX2RldGVjdF9oaWdoKHNyZWdzLCBsYW5lKTsNCj4gPiA+ID4gK30NCj4gPiA+DQo+ID4g
PiBDYW4geW91IGNoYW5nZSB0aGUgY29kZSBzbyB5b3UgY2FuIHVzZSBtc2xlZXAoMSkgaGVyZT8N
Cj4gPiA+DQo+ID4NCj4gPiB3aWxsIHJlcGxhY2UgZGVsYXlzIHdpdGggdXNsZWVwX3JhbmdlKCkN
Cj4gDQo+IE9rLg0KPiANCj4gPiA+ID4gKw0KPiA+ID4gPiArICAgZG8gew0KPiA+ID4gPiArICAg
ICAgICAgICBtZGVsYXkoMTApOw0KPiA+ID4gPiArICAgICAgICAgICBtZW1zZXQobGFuZV9kb3du
LCAwLCBzaXplb2YobGFuZV9kb3duKSk7DQo+ID4gPiA+ICsNCj4gPiA+ID4gKyAgICAgICAgICAg
bGlua191cCA9IF9rc2VyZGVzX2NoZWNrX2xpbmtfc3RhdHVzKGRldiwgc3JlZ3MsDQo+ID4gPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwY3NyX3Jl
Z21hcCwgbGFuZXMsDQo+ID4gPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICBsYW5lc19lbmFibGUsDQo+ID4gPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50X3N0YXRlLA0KPiBsYW5lX2Rvd24p
Ow0KPiA+ID4gPiArDQo+ID4gPiA+ICsgICAgICAgICAgIC8qIGlmIHdlIGRpZCBub3QgZ2V0IGxp
bmsgdXAgdGhlbiB3YWl0IDEwMG1zDQo+ID4gPiA+ICsgICAgICAgICAgICAqIGJlZm9yZSBjYWxs
aW5nIGl0IGFnYWluDQo+ID4gPiA+ICsgICAgICAgICAgICAqLw0KPiA+ID4gPiArICAgICAgICAg
ICBpZiAobGlua191cCkNCj4gPiA+ID4gKyAgICAgICAgICAgICAgICAgICBicmVhazsNCj4gPiA+
ID4gKw0KPiA+ID4gPiArICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgbGFuZXM7IGkrKykgew0K
PiA+ID4gPiArICAgICAgICAgICAgICAgICAgIGlmICgobGFuZXNfZW5hYmxlICYgKDEgPDwgaSkp
ICYmIGxhbmVfZG93bltpXSkNCj4gPiA+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgIGRl
dl9kYmcoZGV2LA0KPiA+ID4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAi
WEdFOiBkZXRlY3RlZCBsYW5lIGRvd24gb24gbGFuZQ0KPiAlZFxuIiwNCj4gPiA+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaSk7DQo+ID4gPiA+ICsgICAgICAgICAgIH0N
Cj4gPiA+ID4gKw0KPiA+ID4gPiArICAgICAgICAgICBpZiAoKytyZXRyaWVzID4gMTAwKQ0KPiA+
ID4gPiArICAgICAgICAgICAgICAgICAgIHJldHVybiAtRVRJTUVET1VUOw0KPiA+ID4gPiArDQo+
ID4gPiA+ICsgICB9IHdoaWxlICghbGlua191cCk7DQo+ID4gPg0KPiA+ID4gYW4gbW9yZSBpbXBv
cnRhbnRseSBoZXJlLiBCbG9ja2luZyB0aGUgQ1BVIGZvciBvdmVyIG9uZSBzZWNvbmQgaXMgbm90
DQo+IGdvb2QuDQo+ID4gPg0KPiA+ID4gQW55IHVzZSBvZiBtZGVsYXkoKSBzaG91bGQgaGF2ZSBh
IGNvbW1lbnQgZXhwbGFpbmluZyB3aHkgeW91IGNhbm5vdCB1c2UNCj4gPiA+IG1zbGVlcCgpIGlu
IHRoYXQgaW5zdGFuY2UuDQo+ID4gPg0KPiA+DQo+ID4gd2lsbCByZXBsYWNlIGRlbGF5cyB3aXRo
IHVzbGVlcF9yYW5nZSgpDQo+IA0KPiBIZXJlIHlvdSBoYXZlIHRvIGJlIGNhcmVmdWwgd2l0aCB0
aGUgdG90YWwgcnVudGltZS4gVXNpbmcgdXNsZWVwX3JhbmdlKCkNCj4gaXMgYSBnb29kIGlkZWEs
IGFuZCB5b3UgY2FuIGhhdmUgYSBwYXJ0aWN1bGFybHkgd2lkZSByYW5nZSwgYnV0IHRoZW4geW91
DQo+IHNob3VsZCBjaGFuZ2VuIHRoZSB0aW1lb3V0IGNvbmRpdGlvbiBmcm9tIG51bWJlciBvZiBy
ZXRyaWVzIHRvIHRvdGFsDQo+IGVsYXBzZWQgdGltZSBsaWtlDQo+IA0KPiAJdW5zaWduZWQgbG9u
ZyB0aW1lb3V0ID0gamlmZmllcyArIEhaOyAvKiAxIHNlY29uZCBtYXhpbXVtICovDQo+IAlkbyB7
DQo+IAkJLi4uDQo+IA0KPiAJCWlmIChsaW5rX3VwKQ0KPiAJCQlicmVhazsNCj4gDQo+IAkJaWYg
KHRpbWVfYWZ0ZXIoamlmZmllcywgdGltZW91dCkNCj4gCQkJcmV0dXJuIC1FVElNRU9VVDsNCj4g
DQo+IAkJdXNsZWVwX3JhbmdlKDEwMDAsIDUwMDAwKTsNCj4gCX0gd2hpbGUgKDEpOw0KPiANCg0K
d2lsbCBkby4gIA0KDQo+IAlBcm5kDQoNClRoYW5rcyBzbyBtdWNoIGZvciB5b3VyIGNvbW1lbnRz
Lg0KV2luZ01hbg0K

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
  2015-10-15 19:21     ` Kishon Vijay Abraham I
  (?)
  (?)
@ 2015-10-16  0:02       ` Kwok, WingMan
  -1 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-16  0:02 UTC (permalink / raw
  To: KISHON VIJAY ABRAHAM, Russell King - ARM Linux
  Cc: robh+dt@kernel.org, pawel.moll@arm.com, mark.rutland@arm.com,
	ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
	Quadros, Roger, Karicheri, Muralidharan, bhelgaas@google.com,
	ssantosh@kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 3118 bytes --]

Hello,

> -----Original Message-----
> From: KISHON VIJAY ABRAHAM
> Sent: Thursday, October 15, 2015 3:22 PM
> To: Russell King - ARM Linux; Kwok, WingMan
> Cc: robh+dt@kernel.org; pawel.moll@arm.com; mark.rutland@arm.com;
> ijc+devicetree@hellion.org.uk; galak@codeaurora.org; Quadros, Roger;
> Karicheri, Muralidharan; bhelgaas@google.com; ssantosh@kernel.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> pci@vger.kernel.org; linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
> 
> Hi,
> 
> On Thursday 15 October 2015 10:21 PM, Russell King - ARM Linux wrote:
> > On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
> >> On TI's Keystone platforms, several peripherals such as the
> >> gbe ethernet switch, 10gbe ethether switch and PCIe controller
> >> require the use of a SerDes for converting SoC parallel data into
> >> serialized data that can be output over a high-speed electrical
> >> interface, and also converting high-speed serial input data
> >> into parallel data that can be processed by the SoC.  The
> >> SerDeses used by those peripherals, though they may be different,
> >> are largely similar in functionality and setup.
> >
> > Given that serdes is not specific to TI, should this be specific to
> > TI, or should there be an effort to come up with something which
> > everyone who has serdes links can make use of?
> >
> > Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
> > 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
> > plethora of SoC specific stuff for this.
> 
> Generally every SoC use it's own serdes and the programming required is
> different for different SoCs. Each of them have their own register map
> and clock programming/regulator programming/reset programming are all
> different.
> 
> However most SoC vendors use the same PHY/SerDes IP to be used by
> multiple controllers like PCIe/SATA/USB in a single SoC and a single PHY
> driver is used for programming all these PHYs.
> 

Thanks so much for the clarifications.

> Thanks
> Kishon
> 

Regards,
WingMan

> >
> > When serdes is combined with SFP cages, the situation becomes much
> > more fun, because the serdes link then needs to become hotpluggable
> > (SFP modules are designed to be hotplugged) which means you have to
> > be able to switch between (at least) 1G SGMII and 1000base-X modes,
> > and probably 10G mode as well.  There's even a SFP module that has
> > a SATA connector on it, though I believe there's no standard for
> > that, and it's more a hardware hack.
> >
> > I've been working in this area but from the Ethernet side on an
> > Armada 38x based board which has a SFP cage on it, though it's
> > slightly simpler there because there is no support (or I believe
> > any desire) to reconfigure the serdes lanes between PCI, ethernet
> > and SATA - that's all setup and initialised for us by uboot.
> >
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-16  0:02       ` Kwok, WingMan
  0 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-16  0:02 UTC (permalink / raw
  To: KISHON VIJAY ABRAHAM, Russell King - ARM Linux
  Cc: robh+dt@kernel.org, pawel.moll@arm.com, mark.rutland@arm.com,
	ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
	Quadros, Roger, Karicheri, Muralidharan, bhelgaas@google.com,
	ssantosh@kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org

Hello,

> -----Original Message-----
> From: KISHON VIJAY ABRAHAM
> Sent: Thursday, October 15, 2015 3:22 PM
> To: Russell King - ARM Linux; Kwok, WingMan
> Cc: robh+dt@kernel.org; pawel.moll@arm.com; mark.rutland@arm.com;
> ijc+devicetree@hellion.org.uk; galak@codeaurora.org; Quadros, Roger;
> Karicheri, Muralidharan; bhelgaas@google.com; ssantosh@kernel.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> pci@vger.kernel.org; linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
> 
> Hi,
> 
> On Thursday 15 October 2015 10:21 PM, Russell King - ARM Linux wrote:
> > On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
> >> On TI's Keystone platforms, several peripherals such as the
> >> gbe ethernet switch, 10gbe ethether switch and PCIe controller
> >> require the use of a SerDes for converting SoC parallel data into
> >> serialized data that can be output over a high-speed electrical
> >> interface, and also converting high-speed serial input data
> >> into parallel data that can be processed by the SoC.  The
> >> SerDeses used by those peripherals, though they may be different,
> >> are largely similar in functionality and setup.
> >
> > Given that serdes is not specific to TI, should this be specific to
> > TI, or should there be an effort to come up with something which
> > everyone who has serdes links can make use of?
> >
> > Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
> > 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
> > plethora of SoC specific stuff for this.
> 
> Generally every SoC use it's own serdes and the programming required is
> different for different SoCs. Each of them have their own register map
> and clock programming/regulator programming/reset programming are all
> different.
> 
> However most SoC vendors use the same PHY/SerDes IP to be used by
> multiple controllers like PCIe/SATA/USB in a single SoC and a single PHY
> driver is used for programming all these PHYs.
> 

Thanks so much for the clarifications.

> Thanks
> Kishon
> 

Regards,
WingMan

> >
> > When serdes is combined with SFP cages, the situation becomes much
> > more fun, because the serdes link then needs to become hotpluggable
> > (SFP modules are designed to be hotplugged) which means you have to
> > be able to switch between (at least) 1G SGMII and 1000base-X modes,
> > and probably 10G mode as well.  There's even a SFP module that has
> > a SATA connector on it, though I believe there's no standard for
> > that, and it's more a hardware hack.
> >
> > I've been working in this area but from the Ethernet side on an
> > Armada 38x based board which has a SFP cage on it, though it's
> > slightly simpler there because there is no support (or I believe
> > any desire) to reconfigure the serdes lanes between PCI, ethernet
> > and SATA - that's all setup and initialised for us by uboot.
> >

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-16  0:02       ` Kwok, WingMan
  0 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-16  0:02 UTC (permalink / raw
  To: linux-arm-kernel

Hello,

> -----Original Message-----
> From: KISHON VIJAY ABRAHAM
> Sent: Thursday, October 15, 2015 3:22 PM
> To: Russell King - ARM Linux; Kwok, WingMan
> Cc: robh+dt at kernel.org; pawel.moll at arm.com; mark.rutland at arm.com;
> ijc+devicetree at hellion.org.uk; galak at codeaurora.org; Quadros, Roger;
> Karicheri, Muralidharan; bhelgaas at google.com; ssantosh at kernel.org;
> devicetree at vger.kernel.org; linux-kernel at vger.kernel.org; linux-
> pci at vger.kernel.org; linux-arm-kernel at lists.infradead.org
> Subject: Re: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
> 
> Hi,
> 
> On Thursday 15 October 2015 10:21 PM, Russell King - ARM Linux wrote:
> > On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
> >> On TI's Keystone platforms, several peripherals such as the
> >> gbe ethernet switch, 10gbe ethether switch and PCIe controller
> >> require the use of a SerDes for converting SoC parallel data into
> >> serialized data that can be output over a high-speed electrical
> >> interface, and also converting high-speed serial input data
> >> into parallel data that can be processed by the SoC.  The
> >> SerDeses used by those peripherals, though they may be different,
> >> are largely similar in functionality and setup.
> >
> > Given that serdes is not specific to TI, should this be specific to
> > TI, or should there be an effort to come up with something which
> > everyone who has serdes links can make use of?
> >
> > Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
> > 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
> > plethora of SoC specific stuff for this.
> 
> Generally every SoC use it's own serdes and the programming required is
> different for different SoCs. Each of them have their own register map
> and clock programming/regulator programming/reset programming are all
> different.
> 
> However most SoC vendors use the same PHY/SerDes IP to be used by
> multiple controllers like PCIe/SATA/USB in a single SoC and a single PHY
> driver is used for programming all these PHYs.
> 

Thanks so much for the clarifications.

> Thanks
> Kishon
> 

Regards,
WingMan

> >
> > When serdes is combined with SFP cages, the situation becomes much
> > more fun, because the serdes link then needs to become hotpluggable
> > (SFP modules are designed to be hotplugged) which means you have to
> > be able to switch between (at least) 1G SGMII and 1000base-X modes,
> > and probably 10G mode as well.  There's even a SFP module that has
> > a SATA connector on it, though I believe there's no standard for
> > that, and it's more a hardware hack.
> >
> > I've been working in this area but from the Ethernet side on an
> > Armada 38x based board which has a SFP cage on it, though it's
> > slightly simpler there because there is no support (or I believe
> > any desire) to reconfigure the serdes lanes between PCI, ethernet
> > and SATA - that's all setup and initialised for us by uboot.
> >

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-16  0:02       ` Kwok, WingMan
  0 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-16  0:02 UTC (permalink / raw
  To: KISHON VIJAY ABRAHAM, Russell King - ARM Linux
  Cc: robh+dt@kernel.org, pawel.moll@arm.com, mark.rutland@arm.com,
	ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
	Quadros, Roger, Karicheri, Muralidharan, bhelgaas@google.com,
	ssantosh@kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org

SGVsbG8sDQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogS0lTSE9OIFZJ
SkFZIEFCUkFIQU0NCj4gU2VudDogVGh1cnNkYXksIE9jdG9iZXIgMTUsIDIwMTUgMzoyMiBQTQ0K
PiBUbzogUnVzc2VsbCBLaW5nIC0gQVJNIExpbnV4OyBLd29rLCBXaW5nTWFuDQo+IENjOiByb2Jo
K2R0QGtlcm5lbC5vcmc7IHBhd2VsLm1vbGxAYXJtLmNvbTsgbWFyay5ydXRsYW5kQGFybS5jb207
DQo+IGlqYytkZXZpY2V0cmVlQGhlbGxpb24ub3JnLnVrOyBnYWxha0Bjb2RlYXVyb3JhLm9yZzsg
UXVhZHJvcywgUm9nZXI7DQo+IEthcmljaGVyaSwgTXVyYWxpZGhhcmFuOyBiaGVsZ2Fhc0Bnb29n
bGUuY29tOyBzc2FudG9zaEBrZXJuZWwub3JnOw0KPiBkZXZpY2V0cmVlQHZnZXIua2VybmVsLm9y
ZzsgbGludXgta2VybmVsQHZnZXIua2VybmVsLm9yZzsgbGludXgtDQo+IHBjaUB2Z2VyLmtlcm5l
bC5vcmc7IGxpbnV4LWFybS1rZXJuZWxAbGlzdHMuaW5mcmFkZWFkLm9yZw0KPiBTdWJqZWN0OiBS
ZTogW1BBVENIIHYxIDAvMl0gQ29tbW9uIFNlckRlcyBkcml2ZXIgZm9yIFRJJ3MgS2V5c3RvbmUg
UGxhdGZvcm1zDQo+IA0KPiBIaSwNCj4gDQo+IE9uIFRodXJzZGF5IDE1IE9jdG9iZXIgMjAxNSAx
MDoyMSBQTSwgUnVzc2VsbCBLaW5nIC0gQVJNIExpbnV4IHdyb3RlOg0KPiA+IE9uIFRodSwgT2N0
IDE1LCAyMDE1IGF0IDEwOjI1OjQzQU0gLTA0MDAsIFdpbmdNYW4gS3dvayB3cm90ZToNCj4gPj4g
T24gVEkncyBLZXlzdG9uZSBwbGF0Zm9ybXMsIHNldmVyYWwgcGVyaXBoZXJhbHMgc3VjaCBhcyB0
aGUNCj4gPj4gZ2JlIGV0aGVybmV0IHN3aXRjaCwgMTBnYmUgZXRoZXRoZXIgc3dpdGNoIGFuZCBQ
Q0llIGNvbnRyb2xsZXINCj4gPj4gcmVxdWlyZSB0aGUgdXNlIG9mIGEgU2VyRGVzIGZvciBjb252
ZXJ0aW5nIFNvQyBwYXJhbGxlbCBkYXRhIGludG8NCj4gPj4gc2VyaWFsaXplZCBkYXRhIHRoYXQg
Y2FuIGJlIG91dHB1dCBvdmVyIGEgaGlnaC1zcGVlZCBlbGVjdHJpY2FsDQo+ID4+IGludGVyZmFj
ZSwgYW5kIGFsc28gY29udmVydGluZyBoaWdoLXNwZWVkIHNlcmlhbCBpbnB1dCBkYXRhDQo+ID4+
IGludG8gcGFyYWxsZWwgZGF0YSB0aGF0IGNhbiBiZSBwcm9jZXNzZWQgYnkgdGhlIFNvQy4gIFRo
ZQ0KPiA+PiBTZXJEZXNlcyB1c2VkIGJ5IHRob3NlIHBlcmlwaGVyYWxzLCB0aG91Z2ggdGhleSBt
YXkgYmUgZGlmZmVyZW50LA0KPiA+PiBhcmUgbGFyZ2VseSBzaW1pbGFyIGluIGZ1bmN0aW9uYWxp
dHkgYW5kIHNldHVwLg0KPiA+DQo+ID4gR2l2ZW4gdGhhdCBzZXJkZXMgaXMgbm90IHNwZWNpZmlj
IHRvIFRJLCBzaG91bGQgdGhpcyBiZSBzcGVjaWZpYyB0bw0KPiA+IFRJLCBvciBzaG91bGQgdGhl
cmUgYmUgYW4gZWZmb3J0IHRvIGNvbWUgdXAgd2l0aCBzb21ldGhpbmcgd2hpY2gNCj4gPiBldmVy
eW9uZSB3aG8gaGFzIHNlcmRlcyBsaW5rcyBjYW4gbWFrZSB1c2Ugb2Y/DQo+ID4NCj4gPiBTZXJk
ZXMgY29tZXMgaW4gbXVsdGlwbGUgZGlmZmVyZW50IGZvcm1zOiBQQ0llLCAxRyBTR01JSSBldGhl
cm5ldCwNCj4gPiAxMDAwYmFzZS1YIGV0aGVybmV0LCAxMGcgZXRoZXJuZXQsIFNBVEEuLi4gSSdk
IGhhdGUgdG8gc2VlIGENCj4gPiBwbGV0aG9yYSBvZiBTb0Mgc3BlY2lmaWMgc3R1ZmYgZm9yIHRo
aXMuDQo+IA0KPiBHZW5lcmFsbHkgZXZlcnkgU29DIHVzZSBpdCdzIG93biBzZXJkZXMgYW5kIHRo
ZSBwcm9ncmFtbWluZyByZXF1aXJlZCBpcw0KPiBkaWZmZXJlbnQgZm9yIGRpZmZlcmVudCBTb0Nz
LiBFYWNoIG9mIHRoZW0gaGF2ZSB0aGVpciBvd24gcmVnaXN0ZXIgbWFwDQo+IGFuZCBjbG9jayBw
cm9ncmFtbWluZy9yZWd1bGF0b3IgcHJvZ3JhbW1pbmcvcmVzZXQgcHJvZ3JhbW1pbmcgYXJlIGFs
bA0KPiBkaWZmZXJlbnQuDQo+IA0KPiBIb3dldmVyIG1vc3QgU29DIHZlbmRvcnMgdXNlIHRoZSBz
YW1lIFBIWS9TZXJEZXMgSVAgdG8gYmUgdXNlZCBieQ0KPiBtdWx0aXBsZSBjb250cm9sbGVycyBs
aWtlIFBDSWUvU0FUQS9VU0IgaW4gYSBzaW5nbGUgU29DIGFuZCBhIHNpbmdsZSBQSFkNCj4gZHJp
dmVyIGlzIHVzZWQgZm9yIHByb2dyYW1taW5nIGFsbCB0aGVzZSBQSFlzLg0KPiANCg0KVGhhbmtz
IHNvIG11Y2ggZm9yIHRoZSBjbGFyaWZpY2F0aW9ucy4NCg0KPiBUaGFua3MNCj4gS2lzaG9uDQo+
IA0KDQpSZWdhcmRzLA0KV2luZ01hbg0KDQo+ID4NCj4gPiBXaGVuIHNlcmRlcyBpcyBjb21iaW5l
ZCB3aXRoIFNGUCBjYWdlcywgdGhlIHNpdHVhdGlvbiBiZWNvbWVzIG11Y2gNCj4gPiBtb3JlIGZ1
biwgYmVjYXVzZSB0aGUgc2VyZGVzIGxpbmsgdGhlbiBuZWVkcyB0byBiZWNvbWUgaG90cGx1Z2dh
YmxlDQo+ID4gKFNGUCBtb2R1bGVzIGFyZSBkZXNpZ25lZCB0byBiZSBob3RwbHVnZ2VkKSB3aGlj
aCBtZWFucyB5b3UgaGF2ZSB0bw0KPiA+IGJlIGFibGUgdG8gc3dpdGNoIGJldHdlZW4gKGF0IGxl
YXN0KSAxRyBTR01JSSBhbmQgMTAwMGJhc2UtWCBtb2RlcywNCj4gPiBhbmQgcHJvYmFibHkgMTBH
IG1vZGUgYXMgd2VsbC4gIFRoZXJlJ3MgZXZlbiBhIFNGUCBtb2R1bGUgdGhhdCBoYXMNCj4gPiBh
IFNBVEEgY29ubmVjdG9yIG9uIGl0LCB0aG91Z2ggSSBiZWxpZXZlIHRoZXJlJ3Mgbm8gc3RhbmRh
cmQgZm9yDQo+ID4gdGhhdCwgYW5kIGl0J3MgbW9yZSBhIGhhcmR3YXJlIGhhY2suDQo+ID4NCj4g
PiBJJ3ZlIGJlZW4gd29ya2luZyBpbiB0aGlzIGFyZWEgYnV0IGZyb20gdGhlIEV0aGVybmV0IHNp
ZGUgb24gYW4NCj4gPiBBcm1hZGEgMzh4IGJhc2VkIGJvYXJkIHdoaWNoIGhhcyBhIFNGUCBjYWdl
IG9uIGl0LCB0aG91Z2ggaXQncw0KPiA+IHNsaWdodGx5IHNpbXBsZXIgdGhlcmUgYmVjYXVzZSB0
aGVyZSBpcyBubyBzdXBwb3J0IChvciBJIGJlbGlldmUNCj4gPiBhbnkgZGVzaXJlKSB0byByZWNv
bmZpZ3VyZSB0aGUgc2VyZGVzIGxhbmVzIGJldHdlZW4gUENJLCBldGhlcm5ldA0KPiA+IGFuZCBT
QVRBIC0gdGhhdCdzIGFsbCBzZXR1cCBhbmQgaW5pdGlhbGlzZWQgZm9yIHVzIGJ5IHVib290Lg0K
PiA+DQo=

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-16  1:00     ` Rob Herring
  0 siblings, 0 replies; 63+ messages in thread
From: Rob Herring @ 2015-10-16  1:00 UTC (permalink / raw
  To: Russell King - ARM Linux
  Cc: WingMan Kwok, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Kishon Vijay Abraham I, Roger Quadros, Murali Karicheri,
	Bjorn Helgaas, Santosh Shilimkar, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org

On Thu, Oct 15, 2015 at 11:51 AM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
>> On TI's Keystone platforms, several peripherals such as the
>> gbe ethernet switch, 10gbe ethether switch and PCIe controller
>> require the use of a SerDes for converting SoC parallel data into
>> serialized data that can be output over a high-speed electrical
>> interface, and also converting high-speed serial input data
>> into parallel data that can be processed by the SoC.  The
>> SerDeses used by those peripherals, though they may be different,
>> are largely similar in functionality and setup.
>
> Given that serdes is not specific to TI, should this be specific to
> TI, or should there be an effort to come up with something which
> everyone who has serdes links can make use of?
>
> Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
> 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
> plethora of SoC specific stuff for this.

The licensed IP I've seen doesn't provide a standard register
interface, but just signals to the IP block. Same with PLL IP. So
we'll probably get to see vendors continue to differentiate on PHY
register design. :)

Rob

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-16  1:00     ` Rob Herring
  0 siblings, 0 replies; 63+ messages in thread
From: Rob Herring @ 2015-10-16  1:00 UTC (permalink / raw
  To: Russell King - ARM Linux
  Cc: WingMan Kwok, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Kishon Vijay Abraham I, Roger Quadros, Murali Karicheri,
	Bjorn Helgaas, Santosh Shilimkar,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org

On Thu, Oct 15, 2015 at 11:51 AM, Russell King - ARM Linux
<linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org> wrote:
> On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
>> On TI's Keystone platforms, several peripherals such as the
>> gbe ethernet switch, 10gbe ethether switch and PCIe controller
>> require the use of a SerDes for converting SoC parallel data into
>> serialized data that can be output over a high-speed electrical
>> interface, and also converting high-speed serial input data
>> into parallel data that can be processed by the SoC.  The
>> SerDeses used by those peripherals, though they may be different,
>> are largely similar in functionality and setup.
>
> Given that serdes is not specific to TI, should this be specific to
> TI, or should there be an effort to come up with something which
> everyone who has serdes links can make use of?
>
> Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
> 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
> plethora of SoC specific stuff for this.

The licensed IP I've seen doesn't provide a standard register
interface, but just signals to the IP block. Same with PLL IP. So
we'll probably get to see vendors continue to differentiate on PHY
register design. :)

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-16  1:00     ` Rob Herring
  0 siblings, 0 replies; 63+ messages in thread
From: Rob Herring @ 2015-10-16  1:00 UTC (permalink / raw
  To: linux-arm-kernel

On Thu, Oct 15, 2015 at 11:51 AM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
>> On TI's Keystone platforms, several peripherals such as the
>> gbe ethernet switch, 10gbe ethether switch and PCIe controller
>> require the use of a SerDes for converting SoC parallel data into
>> serialized data that can be output over a high-speed electrical
>> interface, and also converting high-speed serial input data
>> into parallel data that can be processed by the SoC.  The
>> SerDeses used by those peripherals, though they may be different,
>> are largely similar in functionality and setup.
>
> Given that serdes is not specific to TI, should this be specific to
> TI, or should there be an effort to come up with something which
> everyone who has serdes links can make use of?
>
> Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
> 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
> plethora of SoC specific stuff for this.

The licensed IP I've seen doesn't provide a standard register
interface, but just signals to the IP block. Same with PLL IP. So
we'll probably get to see vendors continue to differentiate on PHY
register design. :)

Rob

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
  2015-10-16  1:00     ` Rob Herring
@ 2015-10-16  8:02       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 63+ messages in thread
From: Russell King - ARM Linux @ 2015-10-16  8:02 UTC (permalink / raw
  To: Rob Herring
  Cc: WingMan Kwok, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Kishon Vijay Abraham I, Roger Quadros, Murali Karicheri,
	Bjorn Helgaas, Santosh Shilimkar, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org

On Thu, Oct 15, 2015 at 08:00:41PM -0500, Rob Herring wrote:
> On Thu, Oct 15, 2015 at 11:51 AM, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
> > On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
> >> On TI's Keystone platforms, several peripherals such as the
> >> gbe ethernet switch, 10gbe ethether switch and PCIe controller
> >> require the use of a SerDes for converting SoC parallel data into
> >> serialized data that can be output over a high-speed electrical
> >> interface, and also converting high-speed serial input data
> >> into parallel data that can be processed by the SoC.  The
> >> SerDeses used by those peripherals, though they may be different,
> >> are largely similar in functionality and setup.
> >
> > Given that serdes is not specific to TI, should this be specific to
> > TI, or should there be an effort to come up with something which
> > everyone who has serdes links can make use of?
> >
> > Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
> > 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
> > plethora of SoC specific stuff for this.
> 
> The licensed IP I've seen doesn't provide a standard register
> interface, but just signals to the IP block. Same with PLL IP. So
> we'll probably get to see vendors continue to differentiate on PHY
> register design. :)

So what?  Network drivers differ radically in register design, yet we
still have a standardised interface to network drivers.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-16  8:02       ` Russell King - ARM Linux
  0 siblings, 0 replies; 63+ messages in thread
From: Russell King - ARM Linux @ 2015-10-16  8:02 UTC (permalink / raw
  To: linux-arm-kernel

On Thu, Oct 15, 2015 at 08:00:41PM -0500, Rob Herring wrote:
> On Thu, Oct 15, 2015 at 11:51 AM, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
> > On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
> >> On TI's Keystone platforms, several peripherals such as the
> >> gbe ethernet switch, 10gbe ethether switch and PCIe controller
> >> require the use of a SerDes for converting SoC parallel data into
> >> serialized data that can be output over a high-speed electrical
> >> interface, and also converting high-speed serial input data
> >> into parallel data that can be processed by the SoC.  The
> >> SerDeses used by those peripherals, though they may be different,
> >> are largely similar in functionality and setup.
> >
> > Given that serdes is not specific to TI, should this be specific to
> > TI, or should there be an effort to come up with something which
> > everyone who has serdes links can make use of?
> >
> > Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
> > 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
> > plethora of SoC specific stuff for this.
> 
> The licensed IP I've seen doesn't provide a standard register
> interface, but just signals to the IP block. Same with PLL IP. So
> we'll probably get to see vendors continue to differentiate on PHY
> register design. :)

So what?  Network drivers differ radically in register design, yet we
still have a standardised interface to network drivers.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
  2015-10-16  8:02       ` Russell King - ARM Linux
@ 2015-10-16 14:10         ` Murali Karicheri
  -1 siblings, 0 replies; 63+ messages in thread
From: Murali Karicheri @ 2015-10-16 14:10 UTC (permalink / raw
  To: Russell King - ARM Linux, Rob Herring
  Cc: WingMan Kwok, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Kishon Vijay Abraham I, Roger Quadros, Bjorn Helgaas,
	Santosh Shilimkar, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org

On 10/16/2015 04:02 AM, Russell King - ARM Linux wrote:
> On Thu, Oct 15, 2015 at 08:00:41PM -0500, Rob Herring wrote:
>> On Thu, Oct 15, 2015 at 11:51 AM, Russell King - ARM Linux
>> <linux@arm.linux.org.uk> wrote:
>>> On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
>>>> On TI's Keystone platforms, several peripherals such as the
>>>> gbe ethernet switch, 10gbe ethether switch and PCIe controller
>>>> require the use of a SerDes for converting SoC parallel data into
>>>> serialized data that can be output over a high-speed electrical
>>>> interface, and also converting high-speed serial input data
>>>> into parallel data that can be processed by the SoC.  The
>>>> SerDeses used by those peripherals, though they may be different,
>>>> are largely similar in functionality and setup.
>>>
>>> Given that serdes is not specific to TI, should this be specific to
>>> TI, or should there be an effort to come up with something which
>>> everyone who has serdes links can make use of?
>>>
Russell,

The serdes on K2 are re-used on multiple hardware blocks as already 
indicated in this thread. It has got multiple lanes, each lane can be 
enabled/disabled, shutdown etc. Isn't generic phy framework added to 
support this type of hardware block? I see some enhancements needed for 
K2 serdes to support monitoring the serdes link and providing a status 
to the higher layer device. So I am not clear what different way you 
would like to handle serdes drivers? Why do you need a new framework?

Murali
>>> Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
>>> 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
>>> plethora of SoC specific stuff for this.
>>
>> The licensed IP I've seen doesn't provide a standard register
>> interface, but just signals to the IP block. Same with PLL IP. So
>> we'll probably get to see vendors continue to differentiate on PHY
>> register design. :)
>
> So what?  Network drivers differ radically in register design, yet we
> still have a standardised interface to network drivers.
>


-- 
Murali Karicheri
Linux Kernel, Keystone

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-16 14:10         ` Murali Karicheri
  0 siblings, 0 replies; 63+ messages in thread
From: Murali Karicheri @ 2015-10-16 14:10 UTC (permalink / raw
  To: linux-arm-kernel

On 10/16/2015 04:02 AM, Russell King - ARM Linux wrote:
> On Thu, Oct 15, 2015 at 08:00:41PM -0500, Rob Herring wrote:
>> On Thu, Oct 15, 2015 at 11:51 AM, Russell King - ARM Linux
>> <linux@arm.linux.org.uk> wrote:
>>> On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
>>>> On TI's Keystone platforms, several peripherals such as the
>>>> gbe ethernet switch, 10gbe ethether switch and PCIe controller
>>>> require the use of a SerDes for converting SoC parallel data into
>>>> serialized data that can be output over a high-speed electrical
>>>> interface, and also converting high-speed serial input data
>>>> into parallel data that can be processed by the SoC.  The
>>>> SerDeses used by those peripherals, though they may be different,
>>>> are largely similar in functionality and setup.
>>>
>>> Given that serdes is not specific to TI, should this be specific to
>>> TI, or should there be an effort to come up with something which
>>> everyone who has serdes links can make use of?
>>>
Russell,

The serdes on K2 are re-used on multiple hardware blocks as already 
indicated in this thread. It has got multiple lanes, each lane can be 
enabled/disabled, shutdown etc. Isn't generic phy framework added to 
support this type of hardware block? I see some enhancements needed for 
K2 serdes to support monitoring the serdes link and providing a status 
to the higher layer device. So I am not clear what different way you 
would like to handle serdes drivers? Why do you need a new framework?

Murali
>>> Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
>>> 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
>>> plethora of SoC specific stuff for this.
>>
>> The licensed IP I've seen doesn't provide a standard register
>> interface, but just signals to the IP block. Same with PLL IP. So
>> we'll probably get to see vendors continue to differentiate on PHY
>> register design. :)
>
> So what?  Network drivers differ radically in register design, yet we
> still have a standardised interface to network drivers.
>


-- 
Murali Karicheri
Linux Kernel, Keystone

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
  2015-10-16  8:02       ` Russell King - ARM Linux
  (?)
@ 2015-10-16 14:14         ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 63+ messages in thread
From: Kishon Vijay Abraham I @ 2015-10-16 14:14 UTC (permalink / raw
  To: Russell King - ARM Linux, Rob Herring
  Cc: WingMan Kwok, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Roger Quadros, Murali Karicheri, Bjorn Helgaas, Santosh Shilimkar,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org

Hi,

On Friday 16 October 2015 01:32 PM, Russell King - ARM Linux wrote:
> On Thu, Oct 15, 2015 at 08:00:41PM -0500, Rob Herring wrote:
>> On Thu, Oct 15, 2015 at 11:51 AM, Russell King - ARM Linux
>> <linux@arm.linux.org.uk> wrote:
>>> On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
>>>> On TI's Keystone platforms, several peripherals such as the
>>>> gbe ethernet switch, 10gbe ethether switch and PCIe controller
>>>> require the use of a SerDes for converting SoC parallel data into
>>>> serialized data that can be output over a high-speed electrical
>>>> interface, and also converting high-speed serial input data
>>>> into parallel data that can be processed by the SoC.  The
>>>> SerDeses used by those peripherals, though they may be different,
>>>> are largely similar in functionality and setup.
>>>
>>> Given that serdes is not specific to TI, should this be specific to
>>> TI, or should there be an effort to come up with something which
>>> everyone who has serdes links can make use of?
>>>
>>> Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
>>> 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
>>> plethora of SoC specific stuff for this.
>>
>> The licensed IP I've seen doesn't provide a standard register
>> interface, but just signals to the IP block. Same with PLL IP. So
>> we'll probably get to see vendors continue to differentiate on PHY
>> register design. :)
> 
> So what?  Network drivers differ radically in register design, yet we
> still have a standardised interface to network drivers.
> 
The PHY framework (in drivers/phy/) already provides a standard
interface to be used by the controller drivers no?

Thanks
Kishon

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-16 14:14         ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 63+ messages in thread
From: Kishon Vijay Abraham I @ 2015-10-16 14:14 UTC (permalink / raw
  To: Russell King - ARM Linux, Rob Herring
  Cc: Mark Rutland, devicetree@vger.kernel.org, Pawel Moll,
	Ian Campbell, WingMan Kwok, linux-pci@vger.kernel.org,
	Santosh Shilimkar, linux-kernel@vger.kernel.org, Murali Karicheri,
	Kumar Gala, Bjorn Helgaas, linux-arm-kernel@lists.infradead.org,
	Roger Quadros

Hi,

On Friday 16 October 2015 01:32 PM, Russell King - ARM Linux wrote:
> On Thu, Oct 15, 2015 at 08:00:41PM -0500, Rob Herring wrote:
>> On Thu, Oct 15, 2015 at 11:51 AM, Russell King - ARM Linux
>> <linux@arm.linux.org.uk> wrote:
>>> On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
>>>> On TI's Keystone platforms, several peripherals such as the
>>>> gbe ethernet switch, 10gbe ethether switch and PCIe controller
>>>> require the use of a SerDes for converting SoC parallel data into
>>>> serialized data that can be output over a high-speed electrical
>>>> interface, and also converting high-speed serial input data
>>>> into parallel data that can be processed by the SoC.  The
>>>> SerDeses used by those peripherals, though they may be different,
>>>> are largely similar in functionality and setup.
>>>
>>> Given that serdes is not specific to TI, should this be specific to
>>> TI, or should there be an effort to come up with something which
>>> everyone who has serdes links can make use of?
>>>
>>> Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
>>> 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
>>> plethora of SoC specific stuff for this.
>>
>> The licensed IP I've seen doesn't provide a standard register
>> interface, but just signals to the IP block. Same with PLL IP. So
>> we'll probably get to see vendors continue to differentiate on PHY
>> register design. :)
> 
> So what?  Network drivers differ radically in register design, yet we
> still have a standardised interface to network drivers.
> 
The PHY framework (in drivers/phy/) already provides a standard
interface to be used by the controller drivers no?

Thanks
Kishon

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-16 14:14         ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 63+ messages in thread
From: Kishon Vijay Abraham I @ 2015-10-16 14:14 UTC (permalink / raw
  To: linux-arm-kernel

Hi,

On Friday 16 October 2015 01:32 PM, Russell King - ARM Linux wrote:
> On Thu, Oct 15, 2015 at 08:00:41PM -0500, Rob Herring wrote:
>> On Thu, Oct 15, 2015 at 11:51 AM, Russell King - ARM Linux
>> <linux@arm.linux.org.uk> wrote:
>>> On Thu, Oct 15, 2015 at 10:25:43AM -0400, WingMan Kwok wrote:
>>>> On TI's Keystone platforms, several peripherals such as the
>>>> gbe ethernet switch, 10gbe ethether switch and PCIe controller
>>>> require the use of a SerDes for converting SoC parallel data into
>>>> serialized data that can be output over a high-speed electrical
>>>> interface, and also converting high-speed serial input data
>>>> into parallel data that can be processed by the SoC.  The
>>>> SerDeses used by those peripherals, though they may be different,
>>>> are largely similar in functionality and setup.
>>>
>>> Given that serdes is not specific to TI, should this be specific to
>>> TI, or should there be an effort to come up with something which
>>> everyone who has serdes links can make use of?
>>>
>>> Serdes comes in multiple different forms: PCIe, 1G SGMII ethernet,
>>> 1000base-X ethernet, 10g ethernet, SATA... I'd hate to see a
>>> plethora of SoC specific stuff for this.
>>
>> The licensed IP I've seen doesn't provide a standard register
>> interface, but just signals to the IP block. Same with PLL IP. So
>> we'll probably get to see vendors continue to differentiate on PHY
>> register design. :)
> 
> So what?  Network drivers differ radically in register design, yet we
> still have a standardised interface to network drivers.
> 
The PHY framework (in drivers/phy/) already provides a standard
interface to be used by the controller drivers no?

Thanks
Kishon

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-15 19:34         ` Arnd Bergmann
  (?)
  (?)
@ 2015-10-19 14:47           ` Kwok, WingMan
  -1 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-19 14:47 UTC (permalink / raw
  To: Arnd Bergmann, Karicheri, Muralidharan
  Cc: linux-arm-kernel@lists.infradead.org, robh+dt@kernel.org,
	pawel.moll@arm.com, mark.rutland@arm.com,
	ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
	KISHON VIJAY ABRAHAM, Quadros, Roger, bhelgaas@google.com,
	ssantosh@kernel.org, linux@arm.linux.org.uk,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 6602 bytes --]

Hi,

> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd@arndb.de]
> Sent: Thursday, October 15, 2015 3:35 PM
> To: Karicheri, Muralidharan
> Cc: linux-arm-kernel@lists.infradead.org; Kwok, WingMan; robh+dt@kernel.org;
> pawel.moll@arm.com; mark.rutland@arm.com; ijc+devicetree@hellion.org.uk;
> galak@codeaurora.org; KISHON VIJAY ABRAHAM; Quadros, Roger;
> bhelgaas@google.com; ssantosh@kernel.org; linux@arm.linux.org.uk;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> pci@vger.kernel.org
> Subject: Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and
> pcie
> 
> On Thursday 15 October 2015 12:01:04 Murali Karicheri wrote:
> >
> > >> + * Redistributions in binary form must reproduce the above copyright
> > >> + * notice, this list of conditions and the following disclaimer in the
> > >> + * documentation and/or other materials provided with the
> > >> + * distribution.
> > >
> > > The current code does not do this when compiled, which might be a
> > > problem for distributors. Can you clarify the license?
> > >
> > Arnd,
> >
> > Can you elaborate on this? I did a grep on the string "Redistributions
> > in binary form must reproduce the above copyright" and I could find
> > several instance of this. So I am not sure what you mean by "The current
> > code does not do this when compiled".
> 
> You write that the binary form of the code must produce the copyright
> notice. I don't see any code that does this. If I was looking in the
> wrong place, let me know.
> 
> 	Arnd

For example, we did a grep of the following 

mypc:linux(personal/linux/serdes) $ grep -rnI "Redistributions in binary form must reproduce the above copyright" ./net/
./net/sunrpc/auth_gss/auth_gss.c:18: *  2. Redistributions in binary form must reproduce the above copyright
./net/sunrpc/auth_gss/gss_mech_switch.c:15: *  2. Redistributions in binary form must reproduce the above copyright
./net/sunrpc/auth_gss/gss_krb5_mech.c:16: *  2. Redistributions in binary form must reproduce the above copyright
./net/bluetooth/ecc.c:10: *  * Redistributions in binary form must reproduce the above copyright
./net/bluetooth/ecc.h:10: *  * Redistributions in binary form must reproduce the above copyright
./net/can/gw.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/can/af_can.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/can/proc.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/can/bcm.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/can/raw.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/can/af_can.h:10: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/discover.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/node.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/netlink_compat.c:10: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/name_distr.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/bearer.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/name_table.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/name_distr.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/addr.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/subscr.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/link.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/net.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/netlink.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/sysctl.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/udp_media.c:11: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/socket.h:11: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/subscr.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/msg.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/name_table.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/msg.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/core.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/socket.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/net.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/bcast.c:14: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/bearer.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/core.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/node.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/addr.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/ib_media.c:17: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/link.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/netlink.h:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/server.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/discover.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/eth_media.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/bcast.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/server.h:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/6lowpan/iphc.c:29: * 2. Redistributions in binary form must reproduce the above copyright
./net/sched/sch_codel.c:17: * 2. Redistributions in binary form must reproduce the above copyright
./net/ieee802154/6lowpan/core.c:27: * 2. Redistributions in binary form must reproduce the above copyright 

Thanks,
WingMan
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-19 14:47           ` Kwok, WingMan
  0 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-19 14:47 UTC (permalink / raw
  To: Arnd Bergmann, Karicheri, Muralidharan
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	pawel.moll-5wv7dgnIgG8@public.gmane.org,
	mark.rutland-5wv7dgnIgG8@public.gmane.org,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg@public.gmane.org,
	galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org,
	KISHON VIJAY ABRAHAM, Quadros, Roger,
	bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org,
	ssantosh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	linux-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

Hi,

> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd@arndb.de]
> Sent: Thursday, October 15, 2015 3:35 PM
> To: Karicheri, Muralidharan
> Cc: linux-arm-kernel@lists.infradead.org; Kwok, WingMan; robh+dt@kernel.org;
> pawel.moll@arm.com; mark.rutland@arm.com; ijc+devicetree@hellion.org.uk;
> galak@codeaurora.org; KISHON VIJAY ABRAHAM; Quadros, Roger;
> bhelgaas@google.com; ssantosh@kernel.org; linux@arm.linux.org.uk;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
> pci@vger.kernel.org
> Subject: Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and
> pcie
> 
> On Thursday 15 October 2015 12:01:04 Murali Karicheri wrote:
> >
> > >> + * Redistributions in binary form must reproduce the above copyright
> > >> + * notice, this list of conditions and the following disclaimer in the
> > >> + * documentation and/or other materials provided with the
> > >> + * distribution.
> > >
> > > The current code does not do this when compiled, which might be a
> > > problem for distributors. Can you clarify the license?
> > >
> > Arnd,
> >
> > Can you elaborate on this? I did a grep on the string "Redistributions
> > in binary form must reproduce the above copyright" and I could find
> > several instance of this. So I am not sure what you mean by "The current
> > code does not do this when compiled".
> 
> You write that the binary form of the code must produce the copyright
> notice. I don't see any code that does this. If I was looking in the
> wrong place, let me know.
> 
> 	Arnd

For example, we did a grep of the following 

mypc:linux(personal/linux/serdes) $ grep -rnI "Redistributions in binary form must reproduce the above copyright" ./net/
./net/sunrpc/auth_gss/auth_gss.c:18: *  2. Redistributions in binary form must reproduce the above copyright
./net/sunrpc/auth_gss/gss_mech_switch.c:15: *  2. Redistributions in binary form must reproduce the above copyright
./net/sunrpc/auth_gss/gss_krb5_mech.c:16: *  2. Redistributions in binary form must reproduce the above copyright
./net/bluetooth/ecc.c:10: *  * Redistributions in binary form must reproduce the above copyright
./net/bluetooth/ecc.h:10: *  * Redistributions in binary form must reproduce the above copyright
./net/can/gw.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/can/af_can.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/can/proc.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/can/bcm.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/can/raw.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/can/af_can.h:10: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/discover.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/node.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/netlink_compat.c:10: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/name_distr.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/bearer.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/name_table.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/name_distr.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/addr.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/subscr.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/link.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/net.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/netlink.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/sysctl.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/udp_media.c:11: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/socket.h:11: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/subscr.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/msg.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/name_table.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/msg.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/core.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/socket.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/net.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/bcast.c:14: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/bearer.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/core.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/node.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/addr.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/ib_media.c:17: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/link.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/netlink.h:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/server.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/discover.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/eth_media.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/bcast.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/server.h:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/6lowpan/iphc.c:29: * 2. Redistributions in binary form must reproduce the above copyright
./net/sched/sch_codel.c:17: * 2. Redistributions in binary form must reproduce the above copyright
./net/ieee802154/6lowpan/core.c:27: * 2. Redistributions in binary form must reproduce the above copyright 

Thanks,
WingMan

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-19 14:47           ` Kwok, WingMan
  0 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-19 14:47 UTC (permalink / raw
  To: linux-arm-kernel

Hi,

> -----Original Message-----
> From: Arnd Bergmann [mailto:arnd at arndb.de]
> Sent: Thursday, October 15, 2015 3:35 PM
> To: Karicheri, Muralidharan
> Cc: linux-arm-kernel at lists.infradead.org; Kwok, WingMan; robh+dt at kernel.org;
> pawel.moll at arm.com; mark.rutland at arm.com; ijc+devicetree at hellion.org.uk;
> galak at codeaurora.org; KISHON VIJAY ABRAHAM; Quadros, Roger;
> bhelgaas at google.com; ssantosh at kernel.org; linux at arm.linux.org.uk;
> devicetree at vger.kernel.org; linux-kernel at vger.kernel.org; linux-
> pci at vger.kernel.org
> Subject: Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and
> pcie
> 
> On Thursday 15 October 2015 12:01:04 Murali Karicheri wrote:
> >
> > >> + * Redistributions in binary form must reproduce the above copyright
> > >> + * notice, this list of conditions and the following disclaimer in the
> > >> + * documentation and/or other materials provided with the
> > >> + * distribution.
> > >
> > > The current code does not do this when compiled, which might be a
> > > problem for distributors. Can you clarify the license?
> > >
> > Arnd,
> >
> > Can you elaborate on this? I did a grep on the string "Redistributions
> > in binary form must reproduce the above copyright" and I could find
> > several instance of this. So I am not sure what you mean by "The current
> > code does not do this when compiled".
> 
> You write that the binary form of the code must produce the copyright
> notice. I don't see any code that does this. If I was looking in the
> wrong place, let me know.
> 
> 	Arnd

For example, we did a grep of the following 

mypc:linux(personal/linux/serdes) $ grep -rnI "Redistributions in binary form must reproduce the above copyright" ./net/
./net/sunrpc/auth_gss/auth_gss.c:18: *  2. Redistributions in binary form must reproduce the above copyright
./net/sunrpc/auth_gss/gss_mech_switch.c:15: *  2. Redistributions in binary form must reproduce the above copyright
./net/sunrpc/auth_gss/gss_krb5_mech.c:16: *  2. Redistributions in binary form must reproduce the above copyright
./net/bluetooth/ecc.c:10: *  * Redistributions in binary form must reproduce the above copyright
./net/bluetooth/ecc.h:10: *  * Redistributions in binary form must reproduce the above copyright
./net/can/gw.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/can/af_can.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/can/proc.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/can/bcm.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/can/raw.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/can/af_can.h:10: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/discover.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/node.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/netlink_compat.c:10: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/name_distr.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/bearer.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/name_table.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/name_distr.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/addr.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/subscr.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/link.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/net.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/netlink.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/sysctl.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/udp_media.c:11: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/socket.h:11: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/subscr.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/msg.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/name_table.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/msg.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/core.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/socket.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/net.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/bcast.c:14: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/bearer.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/core.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/node.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/addr.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/ib_media.c:17: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/link.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/netlink.h:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/server.c:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/discover.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/eth_media.c:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/bcast.h:13: * 2. Redistributions in binary form must reproduce the above copyright
./net/tipc/server.h:12: * 2. Redistributions in binary form must reproduce the above copyright
./net/6lowpan/iphc.c:29: * 2. Redistributions in binary form must reproduce the above copyright
./net/sched/sch_codel.c:17: * 2. Redistributions in binary form must reproduce the above copyright
./net/ieee802154/6lowpan/core.c:27: * 2. Redistributions in binary form must reproduce the above copyright 

Thanks,
WingMan

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-19 14:47           ` Kwok, WingMan
  0 siblings, 0 replies; 63+ messages in thread
From: Kwok, WingMan @ 2015-10-19 14:47 UTC (permalink / raw
  To: Arnd Bergmann, Karicheri, Muralidharan
  Cc: linux-arm-kernel@lists.infradead.org, robh+dt@kernel.org,
	pawel.moll@arm.com, mark.rutland@arm.com,
	ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
	KISHON VIJAY ABRAHAM, Quadros, Roger, bhelgaas@google.com,
	ssantosh@kernel.org, linux@arm.linux.org.uk,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org

SGksDQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogQXJuZCBCZXJnbWFu
biBbbWFpbHRvOmFybmRAYXJuZGIuZGVdDQo+IFNlbnQ6IFRodXJzZGF5LCBPY3RvYmVyIDE1LCAy
MDE1IDM6MzUgUE0NCj4gVG86IEthcmljaGVyaSwgTXVyYWxpZGhhcmFuDQo+IENjOiBsaW51eC1h
cm0ta2VybmVsQGxpc3RzLmluZnJhZGVhZC5vcmc7IEt3b2ssIFdpbmdNYW47IHJvYmgrZHRAa2Vy
bmVsLm9yZzsNCj4gcGF3ZWwubW9sbEBhcm0uY29tOyBtYXJrLnJ1dGxhbmRAYXJtLmNvbTsgaWpj
K2RldmljZXRyZWVAaGVsbGlvbi5vcmcudWs7DQo+IGdhbGFrQGNvZGVhdXJvcmEub3JnOyBLSVNI
T04gVklKQVkgQUJSQUhBTTsgUXVhZHJvcywgUm9nZXI7DQo+IGJoZWxnYWFzQGdvb2dsZS5jb207
IHNzYW50b3NoQGtlcm5lbC5vcmc7IGxpbnV4QGFybS5saW51eC5vcmcudWs7DQo+IGRldmljZXRy
ZWVAdmdlci5rZXJuZWwub3JnOyBsaW51eC1rZXJuZWxAdmdlci5rZXJuZWwub3JnOyBsaW51eC0N
Cj4gcGNpQHZnZXIua2VybmVsLm9yZw0KPiBTdWJqZWN0OiBSZTogW1BBVENIIHYxIDEvMl0gcGh5
OiBrZXlzdG9uZTogc2VyZGVzIGRyaXZlciBmb3IgZ2JlIDEwZ2JlIGFuZA0KPiBwY2llDQo+IA0K
PiBPbiBUaHVyc2RheSAxNSBPY3RvYmVyIDIwMTUgMTI6MDE6MDQgTXVyYWxpIEthcmljaGVyaSB3
cm90ZToNCj4gPg0KPiA+ID4+ICsgKiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVz
dCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodA0KPiA+ID4+ICsgKiBub3RpY2UsIHRoaXMg
bGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIgaW4gdGhlDQo+
ID4gPj4gKyAqIGRvY3VtZW50YXRpb24gYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92aWRlZCB3
aXRoIHRoZQ0KPiA+ID4+ICsgKiBkaXN0cmlidXRpb24uDQo+ID4gPg0KPiA+ID4gVGhlIGN1cnJl
bnQgY29kZSBkb2VzIG5vdCBkbyB0aGlzIHdoZW4gY29tcGlsZWQsIHdoaWNoIG1pZ2h0IGJlIGEN
Cj4gPiA+IHByb2JsZW0gZm9yIGRpc3RyaWJ1dG9ycy4gQ2FuIHlvdSBjbGFyaWZ5IHRoZSBsaWNl
bnNlPw0KPiA+ID4NCj4gPiBBcm5kLA0KPiA+DQo+ID4gQ2FuIHlvdSBlbGFib3JhdGUgb24gdGhp
cz8gSSBkaWQgYSBncmVwIG9uIHRoZSBzdHJpbmcgIlJlZGlzdHJpYnV0aW9ucw0KPiA+IGluIGJp
bmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZSBjb3B5cmlnaHQiIGFuZCBJIGNvdWxk
IGZpbmQNCj4gPiBzZXZlcmFsIGluc3RhbmNlIG9mIHRoaXMuIFNvIEkgYW0gbm90IHN1cmUgd2hh
dCB5b3UgbWVhbiBieSAiVGhlIGN1cnJlbnQNCj4gPiBjb2RlIGRvZXMgbm90IGRvIHRoaXMgd2hl
biBjb21waWxlZCIuDQo+IA0KPiBZb3Ugd3JpdGUgdGhhdCB0aGUgYmluYXJ5IGZvcm0gb2YgdGhl
IGNvZGUgbXVzdCBwcm9kdWNlIHRoZSBjb3B5cmlnaHQNCj4gbm90aWNlLiBJIGRvbid0IHNlZSBh
bnkgY29kZSB0aGF0IGRvZXMgdGhpcy4gSWYgSSB3YXMgbG9va2luZyBpbiB0aGUNCj4gd3Jvbmcg
cGxhY2UsIGxldCBtZSBrbm93Lg0KPiANCj4gCUFybmQNCg0KRm9yIGV4YW1wbGUsIHdlIGRpZCBh
IGdyZXAgb2YgdGhlIGZvbGxvd2luZyANCg0KbXlwYzpsaW51eChwZXJzb25hbC9saW51eC9zZXJk
ZXMpICQgZ3JlcCAtcm5JICJSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXBy
b2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodCIgLi9uZXQvDQouL25ldC9zdW5ycGMvYXV0aF9nc3Mv
YXV0aF9nc3MuYzoxODogKiAgMi4gUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3Qg
cmVwcm9kdWNlIHRoZSBhYm92ZSBjb3B5cmlnaHQNCi4vbmV0L3N1bnJwYy9hdXRoX2dzcy9nc3Nf
bWVjaF9zd2l0Y2guYzoxNTogKiAgMi4gUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11
c3QgcmVwcm9kdWNlIHRoZSBhYm92ZSBjb3B5cmlnaHQNCi4vbmV0L3N1bnJwYy9hdXRoX2dzcy9n
c3Nfa3JiNV9tZWNoLmM6MTY6ICogIDIuIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBt
dXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0DQouL25ldC9ibHVldG9vdGgvZWNjLmM6
MTA6ICogICogUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRo
ZSBhYm92ZSBjb3B5cmlnaHQNCi4vbmV0L2JsdWV0b290aC9lY2MuaDoxMDogKiAgKiBSZWRpc3Ry
aWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdo
dA0KLi9uZXQvY2FuL2d3LmM6MTI6ICogMi4gUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3Jt
IG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZSBjb3B5cmlnaHQNCi4vbmV0L2Nhbi9hZl9jYW4uYzox
MzogKiAyLiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhl
IGFib3ZlIGNvcHlyaWdodA0KLi9uZXQvY2FuL3Byb2MuYzoxMjogKiAyLiBSZWRpc3RyaWJ1dGlv
bnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodA0KLi9u
ZXQvY2FuL2JjbS5jOjEyOiAqIDIuIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0
IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0DQouL25ldC9jYW4vcmF3LmM6MTI6ICogMi4g
UmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZSBj
b3B5cmlnaHQNCi4vbmV0L2Nhbi9hZl9jYW4uaDoxMDogKiAyLiBSZWRpc3RyaWJ1dGlvbnMgaW4g
YmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodA0KLi9uZXQvdGlw
Yy9kaXNjb3Zlci5jOjEzOiAqIDIuIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0
IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0DQouL25ldC90aXBjL25vZGUuaDoxMzogKiAy
LiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3Zl
IGNvcHlyaWdodA0KLi9uZXQvdGlwYy9uZXRsaW5rX2NvbXBhdC5jOjEwOiAqIDIuIFJlZGlzdHJp
YnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0
DQouL25ldC90aXBjL25hbWVfZGlzdHIuaDoxMzogKiAyLiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmlu
YXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodA0KLi9uZXQvdGlwYy9i
ZWFyZXIuYzoxMzogKiAyLiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXBy
b2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodA0KLi9uZXQvdGlwYy9uYW1lX3RhYmxlLmg6MTM6ICog
Mi4gUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92
ZSBjb3B5cmlnaHQNCi4vbmV0L3RpcGMvbmFtZV9kaXN0ci5jOjEzOiAqIDIuIFJlZGlzdHJpYnV0
aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0DQou
L25ldC90aXBjL2FkZHIuYzoxMzogKiAyLiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0g
bXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodA0KLi9uZXQvdGlwYy9zdWJzY3IuaDox
MzogKiAyLiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhl
IGFib3ZlIGNvcHlyaWdodA0KLi9uZXQvdGlwYy9saW5rLmg6MTM6ICogMi4gUmVkaXN0cmlidXRp
b25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZSBjb3B5cmlnaHQNCi4v
bmV0L3RpcGMvbmV0Lmg6MTM6ICogMi4gUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11
c3QgcmVwcm9kdWNlIHRoZSBhYm92ZSBjb3B5cmlnaHQNCi4vbmV0L3RpcGMvbmV0bGluay5jOjEz
OiAqIDIuIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUg
YWJvdmUgY29weXJpZ2h0DQouL25ldC90aXBjL3N5c2N0bC5jOjEyOiAqIDIuIFJlZGlzdHJpYnV0
aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0DQou
L25ldC90aXBjL3VkcF9tZWRpYS5jOjExOiAqIDIuIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkg
Zm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0DQouL25ldC90aXBjL3NvY2tl
dC5oOjExOiAqIDIuIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVj
ZSB0aGUgYWJvdmUgY29weXJpZ2h0DQouL25ldC90aXBjL3N1YnNjci5jOjEzOiAqIDIuIFJlZGlz
dHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJp
Z2h0DQouL25ldC90aXBjL21zZy5jOjEzOiAqIDIuIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkg
Zm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0DQouL25ldC90aXBjL25hbWVf
dGFibGUuYzoxMzogKiAyLiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXBy
b2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodA0KLi9uZXQvdGlwYy9tc2cuaDoxMzogKiAyLiBSZWRp
c3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHly
aWdodA0KLi9uZXQvdGlwYy9jb3JlLmM6MTM6ICogMi4gUmVkaXN0cmlidXRpb25zIGluIGJpbmFy
eSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZSBjb3B5cmlnaHQNCi4vbmV0L3RpcGMvc29j
a2V0LmM6MTM6ICogMi4gUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9k
dWNlIHRoZSBhYm92ZSBjb3B5cmlnaHQNCi4vbmV0L3RpcGMvbmV0LmM6MTM6ICogMi4gUmVkaXN0
cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZSBjb3B5cmln
aHQNCi4vbmV0L3RpcGMvYmNhc3QuYzoxNDogKiAyLiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5
IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodA0KLi9uZXQvdGlwYy9iZWFy
ZXIuaDoxMzogKiAyLiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1
Y2UgdGhlIGFib3ZlIGNvcHlyaWdodA0KLi9uZXQvdGlwYy9jb3JlLmg6MTM6ICogMi4gUmVkaXN0
cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZSBjb3B5cmln
aHQNCi4vbmV0L3RpcGMvbm9kZS5jOjEzOiAqIDIuIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkg
Zm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0DQouL25ldC90aXBjL2FkZHIu
aDoxMzogKiAyLiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2Ug
dGhlIGFib3ZlIGNvcHlyaWdodA0KLi9uZXQvdGlwYy9pYl9tZWRpYS5jOjE3OiAqIDIuIFJlZGlz
dHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJp
Z2h0DQouL25ldC90aXBjL2xpbmsuYzoxMzogKiAyLiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5
IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodA0KLi9uZXQvdGlwYy9uZXRs
aW5rLmg6MTI6ICogMi4gUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9k
dWNlIHRoZSBhYm92ZSBjb3B5cmlnaHQNCi4vbmV0L3RpcGMvc2VydmVyLmM6MTI6ICogMi4gUmVk
aXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZSBjb3B5
cmlnaHQNCi4vbmV0L3RpcGMvZGlzY292ZXIuaDoxMzogKiAyLiBSZWRpc3RyaWJ1dGlvbnMgaW4g
YmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodA0KLi9uZXQvdGlw
Yy9ldGhfbWVkaWEuYzoxMzogKiAyLiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVz
dCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodA0KLi9uZXQvdGlwYy9iY2FzdC5oOjEzOiAq
IDIuIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJv
dmUgY29weXJpZ2h0DQouL25ldC90aXBjL3NlcnZlci5oOjEyOiAqIDIuIFJlZGlzdHJpYnV0aW9u
cyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0DQouL25l
dC82bG93cGFuL2lwaGMuYzoyOTogKiAyLiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0g
bXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodA0KLi9uZXQvc2NoZWQvc2NoX2NvZGVs
LmM6MTc6ICogMi4gUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNl
IHRoZSBhYm92ZSBjb3B5cmlnaHQNCi4vbmV0L2llZWU4MDIxNTQvNmxvd3Bhbi9jb3JlLmM6Mjc6
ICogMi4gUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBh
Ym92ZSBjb3B5cmlnaHQgDQoNClRoYW5rcywNCldpbmdNYW4NCg==

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-19 14:47           ` Kwok, WingMan
@ 2015-10-19 18:50             ` Murali Karicheri
  -1 siblings, 0 replies; 63+ messages in thread
From: Murali Karicheri @ 2015-10-19 18:50 UTC (permalink / raw
  To: Kwok, WingMan, Arnd Bergmann
  Cc: linux-arm-kernel@lists.infradead.org, robh+dt@kernel.org,
	pawel.moll@arm.com, mark.rutland@arm.com,
	ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
	KISHON VIJAY ABRAHAM, Quadros, Roger, bhelgaas@google.com,
	ssantosh@kernel.org, linux@arm.linux.org.uk,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org

On 10/19/2015 10:47 AM, Kwok, WingMan wrote:
> Hi,
>
>> -----Original Message-----
>> From: Arnd Bergmann [mailto:arnd@arndb.de]
>> Sent: Thursday, October 15, 2015 3:35 PM
>> To: Karicheri, Muralidharan
>> Cc: linux-arm-kernel@lists.infradead.org; Kwok, WingMan; robh+dt@kernel.org;
>> pawel.moll@arm.com; mark.rutland@arm.com; ijc+devicetree@hellion.org.uk;
>> galak@codeaurora.org; KISHON VIJAY ABRAHAM; Quadros, Roger;
>> bhelgaas@google.com; ssantosh@kernel.org; linux@arm.linux.org.uk;
>> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-
>> pci@vger.kernel.org
>> Subject: Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and
>> pcie
>>
>> On Thursday 15 October 2015 12:01:04 Murali Karicheri wrote:
>>>
>>>>> + * Redistributions in binary form must reproduce the above copyright
>>>>> + * notice, this list of conditions and the following disclaimer in the
>>>>> + * documentation and/or other materials provided with the
>>>>> + * distribution.
>>>>
>>>> The current code does not do this when compiled, which might be a
>>>> problem for distributors. Can you clarify the license?
>>>>
>>> Arnd,
>>>
>>> Can you elaborate on this? I did a grep on the string "Redistributions
>>> in binary form must reproduce the above copyright" and I could find
>>> several instance of this. So I am not sure what you mean by "The current
>>> code does not do this when compiled".
>>
>> You write that the binary form of the code must produce the copyright
>> notice. I don't see any code that does this. If I was looking in the
>> wrong place, let me know.
>>
>> 	Arnd
>

Thanks Wingman for the response.

Arnd, by your statement 'I don't see any code that does this' do you 
expect a piece of code that embed the license in the binary image? If 
so, that seems weired to me.

Many of the drivers including this patch has the following statement in 
the license that is additional company specific license such as BSD that 
is applicable.

==== Cut and pasted from drivers/crypto/fcrypt.c =======================
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
=========================================================================
I read this as if the source is compiled and distributed as a binary 
either a kernel module ko file or as part of the kernel binary, this 
term must apply. Usually this is part of documentation that goes with 
the product AFAIK.

Murali

> For example, we did a grep of the following
>
> mypc:linux(personal/linux/serdes) $ grep -rnI "Redistributions in binary form must reproduce the above copyright" ./net/
> ./net/sunrpc/auth_gss/auth_gss.c:18: *  2. Redistributions in binary form must reproduce the above copyright
> ./net/sunrpc/auth_gss/gss_mech_switch.c:15: *  2. Redistributions in binary form must reproduce the above copyright
> ./net/sunrpc/auth_gss/gss_krb5_mech.c:16: *  2. Redistributions in binary form must reproduce the above copyright
> ./net/bluetooth/ecc.c:10: *  * Redistributions in binary form must reproduce the above copyright
> ./net/bluetooth/ecc.h:10: *  * Redistributions in binary form must reproduce the above copyright
> ./net/can/gw.c:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/can/af_can.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/can/proc.c:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/can/bcm.c:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/can/raw.c:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/can/af_can.h:10: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/discover.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/node.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/netlink_compat.c:10: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/name_distr.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/bearer.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/name_table.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/name_distr.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/addr.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/subscr.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/link.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/net.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/netlink.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/sysctl.c:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/udp_media.c:11: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/socket.h:11: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/subscr.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/msg.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/name_table.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/msg.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/core.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/socket.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/net.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/bcast.c:14: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/bearer.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/core.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/node.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/addr.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/ib_media.c:17: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/link.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/netlink.h:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/server.c:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/discover.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/eth_media.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/bcast.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/server.h:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/6lowpan/iphc.c:29: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/sched/sch_codel.c:17: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/ieee802154/6lowpan/core.c:27: * 2. Redistributions in binary form must reproduce the above copyright
>
> Thanks,
> WingMan
>


-- 
Murali Karicheri
Linux Kernel, Keystone

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-19 18:50             ` Murali Karicheri
  0 siblings, 0 replies; 63+ messages in thread
From: Murali Karicheri @ 2015-10-19 18:50 UTC (permalink / raw
  To: linux-arm-kernel

On 10/19/2015 10:47 AM, Kwok, WingMan wrote:
> Hi,
>
>> -----Original Message-----
>> From: Arnd Bergmann [mailto:arnd at arndb.de]
>> Sent: Thursday, October 15, 2015 3:35 PM
>> To: Karicheri, Muralidharan
>> Cc: linux-arm-kernel at lists.infradead.org; Kwok, WingMan; robh+dt at kernel.org;
>> pawel.moll at arm.com; mark.rutland at arm.com; ijc+devicetree at hellion.org.uk;
>> galak at codeaurora.org; KISHON VIJAY ABRAHAM; Quadros, Roger;
>> bhelgaas at google.com; ssantosh at kernel.org; linux at arm.linux.org.uk;
>> devicetree at vger.kernel.org; linux-kernel at vger.kernel.org; linux-
>> pci at vger.kernel.org
>> Subject: Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and
>> pcie
>>
>> On Thursday 15 October 2015 12:01:04 Murali Karicheri wrote:
>>>
>>>>> + * Redistributions in binary form must reproduce the above copyright
>>>>> + * notice, this list of conditions and the following disclaimer in the
>>>>> + * documentation and/or other materials provided with the
>>>>> + * distribution.
>>>>
>>>> The current code does not do this when compiled, which might be a
>>>> problem for distributors. Can you clarify the license?
>>>>
>>> Arnd,
>>>
>>> Can you elaborate on this? I did a grep on the string "Redistributions
>>> in binary form must reproduce the above copyright" and I could find
>>> several instance of this. So I am not sure what you mean by "The current
>>> code does not do this when compiled".
>>
>> You write that the binary form of the code must produce the copyright
>> notice. I don't see any code that does this. If I was looking in the
>> wrong place, let me know.
>>
>> 	Arnd
>

Thanks Wingman for the response.

Arnd, by your statement 'I don't see any code that does this' do you 
expect a piece of code that embed the license in the binary image? If 
so, that seems weired to me.

Many of the drivers including this patch has the following statement in 
the license that is additional company specific license such as BSD that 
is applicable.

==== Cut and pasted from drivers/crypto/fcrypt.c =======================
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
=========================================================================
I read this as if the source is compiled and distributed as a binary 
either a kernel module ko file or as part of the kernel binary, this 
term must apply. Usually this is part of documentation that goes with 
the product AFAIK.

Murali

> For example, we did a grep of the following
>
> mypc:linux(personal/linux/serdes) $ grep -rnI "Redistributions in binary form must reproduce the above copyright" ./net/
> ./net/sunrpc/auth_gss/auth_gss.c:18: *  2. Redistributions in binary form must reproduce the above copyright
> ./net/sunrpc/auth_gss/gss_mech_switch.c:15: *  2. Redistributions in binary form must reproduce the above copyright
> ./net/sunrpc/auth_gss/gss_krb5_mech.c:16: *  2. Redistributions in binary form must reproduce the above copyright
> ./net/bluetooth/ecc.c:10: *  * Redistributions in binary form must reproduce the above copyright
> ./net/bluetooth/ecc.h:10: *  * Redistributions in binary form must reproduce the above copyright
> ./net/can/gw.c:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/can/af_can.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/can/proc.c:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/can/bcm.c:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/can/raw.c:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/can/af_can.h:10: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/discover.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/node.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/netlink_compat.c:10: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/name_distr.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/bearer.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/name_table.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/name_distr.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/addr.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/subscr.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/link.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/net.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/netlink.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/sysctl.c:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/udp_media.c:11: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/socket.h:11: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/subscr.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/msg.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/name_table.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/msg.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/core.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/socket.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/net.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/bcast.c:14: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/bearer.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/core.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/node.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/addr.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/ib_media.c:17: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/link.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/netlink.h:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/server.c:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/discover.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/eth_media.c:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/bcast.h:13: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/tipc/server.h:12: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/6lowpan/iphc.c:29: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/sched/sch_codel.c:17: * 2. Redistributions in binary form must reproduce the above copyright
> ./net/ieee802154/6lowpan/core.c:27: * 2. Redistributions in binary form must reproduce the above copyright
>
> Thanks,
> WingMan
>


-- 
Murali Karicheri
Linux Kernel, Keystone

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-19 18:50             ` Murali Karicheri
  (?)
@ 2015-10-20  8:24               ` Arnd Bergmann
  -1 siblings, 0 replies; 63+ messages in thread
From: Arnd Bergmann @ 2015-10-20  8:24 UTC (permalink / raw
  To: Murali Karicheri
  Cc: Kwok, WingMan, linux-arm-kernel@lists.infradead.org,
	robh+dt@kernel.org, pawel.moll@arm.com, mark.rutland@arm.com,
	ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
	KISHON VIJAY ABRAHAM, Quadros, Roger, bhelgaas@google.com,
	ssantosh@kernel.org, linux@arm.linux.org.uk,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org

On Monday 19 October 2015 14:50:57 Murali Karicheri wrote:
> Arnd, by your statement 'I don't see any code that does this' do you 
> expect a piece of code that embed the license in the binary image? If 
> so, that seems weired to me.
> 
> Many of the drivers including this patch has the following statement in 
> the license that is additional company specific license such as BSD that 
> is applicable.
> 
> ==== Cut and pasted from drivers/crypto/fcrypt.c =======================
>   * 2. Redistributions in binary form must reproduce the above copyright
>   *    notice, this list of conditions and the following disclaimer in the
>   *    documentation and/or other materials provided with the distribution.
> =========================================================================
> I read this as if the source is compiled and distributed as a binary 
> either a kernel module ko file or as part of the kernel binary, this 
> term must apply. Usually this is part of documentation that goes with 
> the product AFAIK.

Sorry, my fault. This is indeed the standard BSD license, and
I misread this as having to produce the copyright statement
from the binary itself. Please ignore whatever I said on the
subject.

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-20  8:24               ` Arnd Bergmann
  0 siblings, 0 replies; 63+ messages in thread
From: Arnd Bergmann @ 2015-10-20  8:24 UTC (permalink / raw
  To: Murali Karicheri
  Cc: mark.rutland@arm.com, devicetree@vger.kernel.org,
	linux@arm.linux.org.uk, pawel.moll@arm.com,
	ijc+devicetree@hellion.org.uk, Kwok, WingMan,
	linux-pci@vger.kernel.org, ssantosh@kernel.org,
	linux-kernel@vger.kernel.org, KISHON VIJAY ABRAHAM,
	robh+dt@kernel.org, galak@codeaurora.org, bhelgaas@google.com,
	linux-arm-kernel@lists.infradead.org, Quadros, Roger

On Monday 19 October 2015 14:50:57 Murali Karicheri wrote:
> Arnd, by your statement 'I don't see any code that does this' do you 
> expect a piece of code that embed the license in the binary image? If 
> so, that seems weired to me.
> 
> Many of the drivers including this patch has the following statement in 
> the license that is additional company specific license such as BSD that 
> is applicable.
> 
> ==== Cut and pasted from drivers/crypto/fcrypt.c =======================
>   * 2. Redistributions in binary form must reproduce the above copyright
>   *    notice, this list of conditions and the following disclaimer in the
>   *    documentation and/or other materials provided with the distribution.
> =========================================================================
> I read this as if the source is compiled and distributed as a binary 
> either a kernel module ko file or as part of the kernel binary, this 
> term must apply. Usually this is part of documentation that goes with 
> the product AFAIK.

Sorry, my fault. This is indeed the standard BSD license, and
I misread this as having to produce the copyright statement
from the binary itself. Please ignore whatever I said on the
subject.

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-20  8:24               ` Arnd Bergmann
  0 siblings, 0 replies; 63+ messages in thread
From: Arnd Bergmann @ 2015-10-20  8:24 UTC (permalink / raw
  To: linux-arm-kernel

On Monday 19 October 2015 14:50:57 Murali Karicheri wrote:
> Arnd, by your statement 'I don't see any code that does this' do you 
> expect a piece of code that embed the license in the binary image? If 
> so, that seems weired to me.
> 
> Many of the drivers including this patch has the following statement in 
> the license that is additional company specific license such as BSD that 
> is applicable.
> 
> ==== Cut and pasted from drivers/crypto/fcrypt.c =======================
>   * 2. Redistributions in binary form must reproduce the above copyright
>   *    notice, this list of conditions and the following disclaimer in the
>   *    documentation and/or other materials provided with the distribution.
> =========================================================================
> I read this as if the source is compiled and distributed as a binary 
> either a kernel module ko file or as part of the kernel binary, this 
> term must apply. Usually this is part of documentation that goes with 
> the product AFAIK.

Sorry, my fault. This is indeed the standard BSD license, and
I misread this as having to produce the copyright statement
from the binary itself. Please ignore whatever I said on the
subject.

	Arnd

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-20  8:24               ` Arnd Bergmann
@ 2015-10-20 15:11                 ` Murali Karicheri
  -1 siblings, 0 replies; 63+ messages in thread
From: Murali Karicheri @ 2015-10-20 15:11 UTC (permalink / raw
  To: Arnd Bergmann
  Cc: Kwok, WingMan, linux-arm-kernel@lists.infradead.org,
	robh+dt@kernel.org, pawel.moll@arm.com, mark.rutland@arm.com,
	ijc+devicetree@hellion.org.uk, galak@codeaurora.org,
	KISHON VIJAY ABRAHAM, Quadros, Roger, bhelgaas@google.com,
	ssantosh@kernel.org, linux@arm.linux.org.uk,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org

On 10/20/2015 04:24 AM, Arnd Bergmann wrote:
> On Monday 19 October 2015 14:50:57 Murali Karicheri wrote:
>> Arnd, by your statement 'I don't see any code that does this' do you
>> expect a piece of code that embed the license in the binary image? If
>> so, that seems weired to me.
>>
>> Many of the drivers including this patch has the following statement in
>> the license that is additional company specific license such as BSD that
>> is applicable.
>>
>> ==== Cut and pasted from drivers/crypto/fcrypt.c =======================
>>    * 2. Redistributions in binary form must reproduce the above copyright
>>    *    notice, this list of conditions and the following disclaimer in the
>>    *    documentation and/or other materials provided with the distribution.
>> =========================================================================
>> I read this as if the source is compiled and distributed as a binary
>> either a kernel module ko file or as part of the kernel binary, this
>> term must apply. Usually this is part of documentation that goes with
>> the product AFAIK.
>
> Sorry, my fault. This is indeed the standard BSD license, and
> I misread this as having to produce the copyright statement
> from the binary itself. Please ignore whatever I said on the
> subject.
>
> 	Arnd
>
Thanks Arnd for the clarification.

-- 
Murali Karicheri
Linux Kernel, Keystone

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie
@ 2015-10-20 15:11                 ` Murali Karicheri
  0 siblings, 0 replies; 63+ messages in thread
From: Murali Karicheri @ 2015-10-20 15:11 UTC (permalink / raw
  To: linux-arm-kernel

On 10/20/2015 04:24 AM, Arnd Bergmann wrote:
> On Monday 19 October 2015 14:50:57 Murali Karicheri wrote:
>> Arnd, by your statement 'I don't see any code that does this' do you
>> expect a piece of code that embed the license in the binary image? If
>> so, that seems weired to me.
>>
>> Many of the drivers including this patch has the following statement in
>> the license that is additional company specific license such as BSD that
>> is applicable.
>>
>> ==== Cut and pasted from drivers/crypto/fcrypt.c =======================
>>    * 2. Redistributions in binary form must reproduce the above copyright
>>    *    notice, this list of conditions and the following disclaimer in the
>>    *    documentation and/or other materials provided with the distribution.
>> =========================================================================
>> I read this as if the source is compiled and distributed as a binary
>> either a kernel module ko file or as part of the kernel binary, this
>> term must apply. Usually this is part of documentation that goes with
>> the product AFAIK.
>
> Sorry, my fault. This is indeed the standard BSD license, and
> I misread this as having to produce the copyright statement
> from the binary itself. Please ignore whatever I said on the
> subject.
>
> 	Arnd
>
Thanks Arnd for the clarification.

-- 
Murali Karicheri
Linux Kernel, Keystone

^ permalink raw reply	[flat|nested] 63+ messages in thread

end of thread, other threads:[~2015-10-20 15:12 UTC | newest]

Thread overview: 63+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-15 14:25 [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms WingMan Kwok
2015-10-15 14:25 ` WingMan Kwok
2015-10-15 14:25 ` WingMan Kwok
2015-10-15 14:25 ` [PATCH v1 1/2] phy: keystone: serdes driver for gbe 10gbe and pcie WingMan Kwok
2015-10-15 14:25   ` WingMan Kwok
2015-10-15 14:25   ` WingMan Kwok
2015-10-15 14:51   ` Arnd Bergmann
2015-10-15 14:51     ` Arnd Bergmann
2015-10-15 16:01     ` Murali Karicheri
2015-10-15 16:01       ` Murali Karicheri
2015-10-15 16:01       ` Murali Karicheri
2015-10-15 19:34       ` Arnd Bergmann
2015-10-15 19:34         ` Arnd Bergmann
2015-10-19 14:47         ` Kwok, WingMan
2015-10-19 14:47           ` Kwok, WingMan
2015-10-19 14:47           ` Kwok, WingMan
2015-10-19 14:47           ` Kwok, WingMan
2015-10-19 18:50           ` Murali Karicheri
2015-10-19 18:50             ` Murali Karicheri
2015-10-20  8:24             ` Arnd Bergmann
2015-10-20  8:24               ` Arnd Bergmann
2015-10-20  8:24               ` Arnd Bergmann
2015-10-20 15:11               ` Murali Karicheri
2015-10-20 15:11                 ` Murali Karicheri
2015-10-15 20:08     ` Kwok, WingMan
2015-10-15 20:08       ` Kwok, WingMan
2015-10-15 20:08       ` Kwok, WingMan
2015-10-15 20:08       ` Kwok, WingMan
2015-10-15 20:53       ` Arnd Bergmann
2015-10-15 20:53         ` Arnd Bergmann
2015-10-15 23:57         ` Kwok, WingMan
2015-10-15 23:57           ` Kwok, WingMan
2015-10-15 23:57           ` Kwok, WingMan
2015-10-15 23:57           ` Kwok, WingMan
2015-10-15 16:14   ` Rob Herring
2015-10-15 16:14     ` Rob Herring
2015-10-15 23:53     ` Kwok, WingMan
2015-10-15 23:53       ` Kwok, WingMan
2015-10-15 23:53       ` Kwok, WingMan
2015-10-15 23:53       ` Kwok, WingMan
2015-10-15 14:25 ` [PATCH v1 2/2] PCI: keystone: update to use generic keystone serdes driver WingMan Kwok
2015-10-15 14:25   ` WingMan Kwok
2015-10-15 14:25   ` WingMan Kwok
2015-10-15 16:51 ` [PATCH v1 0/2] Common SerDes driver for TI's Keystone Platforms Russell King - ARM Linux
2015-10-15 16:51   ` Russell King - ARM Linux
2015-10-15 16:51   ` Russell King - ARM Linux
2015-10-15 19:21   ` Kishon Vijay Abraham I
2015-10-15 19:21     ` Kishon Vijay Abraham I
2015-10-15 19:21     ` Kishon Vijay Abraham I
2015-10-16  0:02     ` Kwok, WingMan
2015-10-16  0:02       ` Kwok, WingMan
2015-10-16  0:02       ` Kwok, WingMan
2015-10-16  0:02       ` Kwok, WingMan
2015-10-16  1:00   ` Rob Herring
2015-10-16  1:00     ` Rob Herring
2015-10-16  1:00     ` Rob Herring
2015-10-16  8:02     ` Russell King - ARM Linux
2015-10-16  8:02       ` Russell King - ARM Linux
2015-10-16 14:10       ` Murali Karicheri
2015-10-16 14:10         ` Murali Karicheri
2015-10-16 14:14       ` Kishon Vijay Abraham I
2015-10-16 14:14         ` Kishon Vijay Abraham I
2015-10-16 14:14         ` Kishon Vijay Abraham I

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.