linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] Common SerDes driver for TI's Keystone Platforms
@ 2015-10-13 18:04 WingMan Kwok
  2015-10-13 18:04 ` [PATCH 1/3] phy: keystone: serdes driver for gbe 10gbe and pcie WingMan Kwok
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: WingMan Kwok @ 2015-10-13 18:04 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)

WingMan Kwok (3):
  phy: keystone: serdes driver for gbe 10gbe and pcie
  PCI: keystone: update to use generic keystone serdes driver
  ARM: keystone: dts: add PCI serdes driver bindings

 Documentation/devicetree/bindings/phy/ti-phy.txt |  256 +++
 arch/arm/boot/dts/k2e.dtsi                       |   24 +
 arch/arm/boot/dts/keystone.dtsi                  |   25 +
 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                | 2465 ++++++++++++++++++++++
 8 files changed, 2826 insertions(+), 9 deletions(-)
 create mode 100644 drivers/phy/phy-keystone-serdes.c

-- 
1.7.9.5


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

* [PATCH 1/3] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-13 18:04 [PATCH 0/3] Common SerDes driver for TI's Keystone Platforms WingMan Kwok
@ 2015-10-13 18:04 ` WingMan Kwok
  2015-10-13 18:33   ` Mark Rutland
  2015-10-13 22:58   ` Kishon Vijay Abraham I
  2015-10-13 18:04 ` [PATCH 2/3] PCI: keystone: update to use generic keystone serdes driver WingMan Kwok
  2015-10-13 18:04 ` [PATCH 3/3] ARM: keystone: dts: add PCI serdes driver bindings WingMan Kwok
  2 siblings, 2 replies; 10+ messages in thread
From: WingMan Kwok @ 2015-10-13 18:04 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.

Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
---
 Documentation/devicetree/bindings/phy/ti-phy.txt |  256 +++
 drivers/phy/Kconfig                              |    8 +
 drivers/phy/Makefile                             |    1 +
 drivers/phy/phy-keystone-serdes.c                | 2465 ++++++++++++++++++++++
 4 files changed, 2730 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..231716e 100644
--- a/Documentation/devicetree/bindings/phy/ti-phy.txt
+++ b/Documentation/devicetree/bindings/phy/ti-phy.txt
@@ -115,4 +115,260 @@ 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:
+	* "reg_serdes"
+		- name of the reg SerDes register set
+ - #phy-cells:
+	* From the generic phy bindings, must be 0;
+ - max-lanes:
+	* Number of lanes in SerDes.
+ - phy-type: should be one of
+	* "sgmii"
+	* "xge"
+	* "pcie"
+
+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.
+ - refclk-khz:
+	* Reference clock rate of SerDes in kHz.
+ - link-rate-kbps:
+	* SerDes link rate to be configured, in kbps.
+ - 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 outpust voltage
+	  configurations.
+	* Must be array of 5 integers.
+ - debug:
+	* enable more debug messages.
+
+Example for Keystone K2E GBE:
+-----------------------------
+
+gbe_serdes0: gbe_serdes@232a000 {
+	#phy-cells		= <0>;
+	compatible		= "ti,keystone-serdes-gbe";
+	reg			= <0x0232a000 0x2000>;
+	reg-names		= "reg_serdes";
+	refclk-khz		= <156250>;
+	link-rate-kbps		= <1250000>;
+	phy-type		= "sgmii";
+	max-lanes		= <4>;
+	lane0 {
+		control-rate	= <2>; /* quart */
+		rx-start	= <7 5>;
+		rx-force	= <1 1>;
+		tx-coeff	= <0 0 0 12 4>;
+		       /* c1 c2 cm att vreg */
+	};
+	lane1 {
+		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		= "reg_serdes";
+	refclk-khz		= <156250>;
+	link-rate-kbps		= <1250000>;
+	phy-type		= "sgmii";
+	max-lanes		= <4>;
+	lane0 {
+		control-rate	= <2>; /* quart */
+		rx-start	= <7 5>;
+		rx-force	= <1 1>;
+		tx-coeff	= <0 0 0 12 4>;
+		       /* c1 c2 cm att vreg */
+	};
+	lane1 {
+		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-phy";
+		reg = <0x02320000 0x4000>, <0x21800000 0x2000>;
+		reg-names = "reg_serdes", "reg_peripheral";
+		phy-type = "pcie";
+		max-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		= "reg_serdes";
+	refclk-khz		= <156250>;
+	link-rate-kbps		= <10312500>;
+	phy-type		= "xge";
+	max-lanes		= <2>;
+	syscon-peripheral	= <&xgbe_subsys>;
+	syscon-link		= <&xgbe_pcsr>;
+	lane0 {
+		/*disable;*/
+		/*loopback;*/
+		control-rate	= <0>; /* full */
+		rx-start	= <7 5>;
+		rx-force	= <1 1>;
+		tx-coeff	= <2 0 0 12 4>;
+			/* c1 c2 cm att vreg */
+	};
+	lane1 {
+		/*disable;*/
+		/*loopback;*/
+		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..c73d4de
--- /dev/null
+++ b/drivers/phy/phy-keystone-serdes.c
@@ -0,0 +1,2465 @@
+/*
+ * 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))
+
+/* bit mask from bit-a to bit-b inclusive */
+#define MASK(msb, lsb) \
+	((((msb) - (lsb)) == 31) ? 0xffffffff :  \
+		((((u32)1 << ((msb) - (lsb) + 1)) - 1) << (lsb)))
+
+/* 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)), MASK((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 for_each_lane_return(func, sc, r)		\
+	do {						\
+		int i;					\
+		(r) = 0;				\
+		for (i = 0; i < (sc)->lanes; i++) {	\
+			(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	MASK(21, 20)
+#define ANEG_LINK_CTL_1GKX_MASK		MASK(17, 16)
+#define ANEG_LINK_CTL_1G10G_MASK \
+	(ANEG_LINK_CTL_10GKR_MASK | ANEG_LINK_CTL_1GKX_MASK)
+
+#define ANEG_1G_10G_OPT_MASK	MASK(7, 5)
+
+#define SERDES_REG_INDEX		0
+
+/* 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 Reference clock KHz */
+enum KSERDES_CLOCK_RATE {
+	KSERDES_CLOCK_RATE_100M		= 100000,
+	KSERDES_CLOCK_RATE_122P88M	= 122880,
+	KSERDES_CLOCK_RATE_125M		= 125000,
+	KSERDES_CLOCK_RATE_153P6M	= 153600,
+	KSERDES_CLOCK_RATE_156P25M	= 156250,
+	KSERDES_CLOCK_RATE_312P5M	= 312500,
+};
+
+/* 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 {
+	u32				enable;
+	u32				ctrl_rate;
+	struct kserdes_tx_coeff		tx_coeff;
+	struct kserdes_equalizer	rx_start;
+	struct kserdes_equalizer	rx_force;
+	u32				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_CLOCK_RATE		clk_rate;
+	enum KSERDES_PHY_TYPE		phy_type;
+	u32				lanes;
+	bool				debug;
+	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;
+	u32				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)
+{
+	if ((sc->clk_rate != KSERDES_CLOCK_RATE_156P25M) ||
+	    (sc->link_rate != KSERDES_LINK_RATE_1P25G))
+		return -EINVAL;
+
+	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,
+			   MASK(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),
+					   MASK(7, 0), 0x19);
+			regmap_update_bits(pcsr_regmap, PCSR_RX_CTL(i),
+					   MASK(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 64B data mem */
+	kserdes_writel(sc->regs, MEM_ADR_REG, 0x0000ffc0);
+
+	for (i = 0; i < 11; i++)
+		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)
+{
+	if (sc->clk_rate != KSERDES_CLOCK_RATE_156P25M)
+		return -EINVAL;
+
+	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)
+{
+	if ((sc->clk_rate != KSERDES_CLOCK_RATE_100M) ||
+	    (sc->link_rate != KSERDES_LINK_RATE_5G))
+		return -EINVAL;
+
+	return kserdes_load_init_fw(sc, ks2_pcie_serdes_firmwares,
+				    ARRAY_SIZE(ks2_pcie_serdes_firmwares));
+}
+
+static void kserdes_show_fw_config(struct kserdes_config *sc)
+{
+	struct kserdes_fw_config *fw = &sc->fw;
+
+	dev_info(sc->dev, "fw configs:\n");
+	dev_info(sc->dev, "  lane_configs: 0x%02x, 0x%02x\n",
+		 fw->lane_config[0], fw->lane_config[1]);
+	dev_info(sc->dev,
+		 "  lnk_loss_wait: %d, lane_seeds: 0x%08x, fast_train: 0x%08x\n",
+		 fw->link_loss_wait, fw->lane_seeds, fw->fast_train);
+}
+
+static void kserdes_show_lane_config(struct device *dev,
+				     struct kserdes_lane_config *lc)
+{
+	dev_info(dev, "%s\n", lc->enable ? "enable" : "disable");
+	dev_info(dev, "ctrl_rate 0x%x\n", lc->ctrl_rate);
+	dev_info(dev, "rx_start %u %u\n",
+		 lc->rx_start.att, lc->rx_start.boost);
+	dev_info(dev, "rx_force %u %u\n",
+		 lc->rx_force.att, lc->rx_force.boost);
+	dev_info(dev, "tx_coeff %u %u %u %u %u\n",
+		 lc->tx_coeff.c1, lc->tx_coeff.c2, lc->tx_coeff.cm,
+		 lc->tx_coeff.att, lc->tx_coeff.vreg);
+	dev_info(dev, "loopback %u\n", lc->loopback);
+}
+
+static void kserdes_show_config(struct kserdes_config *sc)
+{
+	u32 i;
+
+	if (!sc->debug)
+		return;
+
+	dev_info(sc->dev, "serdes regs 0x%p\n", sc->regs);
+	if (sc->peripheral_regmap)
+		dev_info(sc->dev, "peripheral regmap handle defined\n");
+	dev_info(sc->dev, "phy_type %u\n", sc->phy_type);
+	dev_info(sc->dev, "clk_rate %u\n", sc->clk_rate);
+	dev_info(sc->dev, "link_rate %u\n", sc->link_rate);
+	dev_info(sc->dev, "lanes %u\n", sc->lanes);
+	if ((sc->phy_type == KSERDES_PHY_XGE) && sc->pcsr_regmap)
+		dev_info(sc->dev, "pcsr regmap handle defined\n");
+
+	if (sc->firmware) {
+		kserdes_show_fw_config(sc);
+		return;
+	} else if (sc->init_fw) {
+		dev_info(sc->dev, "init fw: %s\n", sc->init_fw);
+	}
+
+	dev_info(sc->dev, "rx-force-%s\n",
+		 (sc->rx_force_enable ? "enable" : "disable"));
+
+	for (i = 0; i < sc->lanes; i++) {
+		dev_info(sc->dev, "lane[%u]:\n", i);
+		kserdes_show_lane_config(sc->dev, &sc->lane[i]);
+	}
+}
+
+static int kserdes_lanes_enable(struct kserdes_config *sc)
+{
+	int ret = -EINVAL;
+
+	if (sc->phy_type == KSERDES_PHY_SGMII)
+		ret = kserdes_sgmii_lanes_enable(sc);
+	else if (sc->phy_type == KSERDES_PHY_XGE)
+		ret = kserdes_xge_lanes_enable(sc);
+	else if (sc->phy_type == KSERDES_PHY_PCIE)
+		ret = kserdes_pcie_lanes_enable(sc);
+
+	return ret;
+}
+
+static int kserdes_init(struct phy *phy)
+{
+	struct kserdes_dev *sd = phy_get_drvdata(phy);
+	struct kserdes_config *sc = &sd->sc;
+	int ret;
+
+	if (sc->phy_type == KSERDES_PHY_SGMII)
+		ret = kserdes_sgmii_init(sc);
+	else if (sc->phy_type == KSERDES_PHY_XGE)
+		ret = kserdes_xge_init(sc);
+	else if (sc->phy_type == KSERDES_PHY_PCIE)
+		ret = kserdes_pcie_init(sc);
+	else
+		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_info(sd->dev, "serdes config done lanes(mask) 0x%x\n", ret);
+
+done:
+	return ret;
+}
+
+struct phy *kserdes_phy_xlate(struct device *dev, struct of_phandle_args *args)
+{
+	struct kserdes_dev *sd = dev_get_drvdata(dev);
+
+	return sd->phy;
+}
+
+static int kserdes_get_lane_bindings(struct device *dev,
+				     struct device_node *np,
+				     struct kserdes_lane_config *lc)
+{
+	struct kserdes_equalizer *eq;
+	struct kserdes_tx_coeff *tc;
+
+	if (of_find_property(np, "disable", NULL))
+		lc->enable = 0;
+	else
+		lc->enable = 1;
+
+	dev_dbg(dev, "lane enable: %d\n", lc->enable);
+
+	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 = 1;
+	else
+		lc->loopback = 0;
+
+	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->clk_rate		= KSERDES_CLOCK_RATE_156P25M;
+	sc->link_rate		= KSERDES_LINK_RATE_1P25G;
+	sc->lanes		= 4;
+	sc->rx_force_enable	= 0;
+
+	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->clk_rate		= KSERDES_CLOCK_RATE_156P25M;
+	sc->link_rate		= KSERDES_LINK_RATE_10P3125G;
+	sc->lanes		= 2;
+	sc->rx_force_enable	= 0;
+
+	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->clk_rate		= KSERDES_CLOCK_RATE_100M;
+	sc->link_rate		= KSERDES_LINK_RATE_5G;
+	sc->lanes		= 2;
+	sc->rx_force_enable	= 0;
+
+	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_get_properties(struct kserdes_dev *sd,
+				  struct device_node *np)
+{
+	struct kserdes_config *sc = &sd->sc;
+	struct device_node *lp;
+	struct device *dev = sd->dev;
+	struct resource res;
+	void __iomem *regs;
+	const char *phy_type;
+	char name[16] = {'l', 'a', 'n', 'e'};
+	int ret, i;
+
+	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;
+
+	ret = of_property_read_string(np, "phy-type", &phy_type);
+	if (!ret) {
+		if (strcmp(phy_type, "sgmii") == 0)
+			sc->phy_type = KSERDES_PHY_SGMII;
+		else if (strcmp(phy_type, "xge") == 0)
+			sc->phy_type = KSERDES_PHY_XGE;
+		else if (strcmp(phy_type, "pcie") == 0)
+			sc->phy_type = KSERDES_PHY_PCIE;
+		else
+			return -EINVAL;
+	}
+
+	sc->dev = dev;
+
+	/* Set the defaults base on phy type */
+	kserdes_set_defaults(sc, sc->phy_type);
+
+	if (of_property_read_bool(np, "syscon-peripheral")) {
+		sc->peripheral_regmap =
+			syscon_regmap_lookup_by_phandle(np,
+							"syscon-peripheral");
+		if (IS_ERR(sc->peripheral_regmap)) {
+			dev_err(sc->dev,
+				"failed to get syscon-peripheral regmap\n");
+			return PTR_ERR(sc->peripheral_regmap);
+		}
+	}
+
+	if (of_property_read_bool(np, "syscon-link")) {
+		sc->pcsr_regmap =
+			syscon_regmap_lookup_by_phandle(np, "syscon-link");
+		if (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, "refclk-khz", &sc->clk_rate))
+		dev_info(dev, "use default refclk-khz: %u\n", sc->clk_rate);
+
+	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, "max-lanes", &sc->lanes))
+		dev_info(dev, "use default max-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);
+	}
+
+	sc->debug = of_property_read_bool(np, "debug");
+
+	if (of_find_property(np, "rx-force-enable", NULL))
+		sc->rx_force_enable = 1;
+	else
+		sc->rx_force_enable = 0;
+
+	for (i = 0; i < sc->lanes; i++) {
+		sprintf(&name[4], "%d", i);
+		lp = of_find_node_by_name(np, name);
+		if (lp) {
+			if (kserdes_get_lane_bindings(dev, lp, &sc->lane[i]))
+				return -EINVAL;
+		}
+	}
+
+	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_get_properties(sd, np);
+	if (ret)
+		return ret;
+
+	kserdes_show_config(&sd->sc);
+
+	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,
+						     kserdes_phy_xlate);
+
+	if (IS_ERR(phy_provider))
+		return PTR_ERR_OR_ZERO(phy_provider);
+
+	dev_info(&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",
+		.owner = THIS_MODULE,
+	}
+};
+
+static int __init keystone_serdes_phy_init(void)
+{
+	return platform_driver_register(&kserdes_driver);
+}
+subsys_initcall(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] 10+ messages in thread

* [PATCH 2/3] PCI: keystone: update to use generic keystone serdes driver
  2015-10-13 18:04 [PATCH 0/3] Common SerDes driver for TI's Keystone Platforms WingMan Kwok
  2015-10-13 18:04 ` [PATCH 1/3] phy: keystone: serdes driver for gbe 10gbe and pcie WingMan Kwok
@ 2015-10-13 18:04 ` WingMan Kwok
  2015-10-13 18:04 ` [PATCH 3/3] ARM: keystone: dts: add PCI serdes driver bindings WingMan Kwok
  2 siblings, 0 replies; 10+ messages in thread
From: WingMan Kwok @ 2015-10-13 18:04 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.

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] 10+ messages in thread

* [PATCH 3/3] ARM: keystone: dts: add PCI serdes driver bindings
  2015-10-13 18:04 [PATCH 0/3] Common SerDes driver for TI's Keystone Platforms WingMan Kwok
  2015-10-13 18:04 ` [PATCH 1/3] phy: keystone: serdes driver for gbe 10gbe and pcie WingMan Kwok
  2015-10-13 18:04 ` [PATCH 2/3] PCI: keystone: update to use generic keystone serdes driver WingMan Kwok
@ 2015-10-13 18:04 ` WingMan Kwok
  2015-10-13 18:23   ` Murali Karicheri
  2 siblings, 1 reply; 10+ messages in thread
From: WingMan Kwok @ 2015-10-13 18:04 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

Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
---
 arch/arm/boot/dts/k2e.dtsi      |   24 ++++++++++++++++++++++++
 arch/arm/boot/dts/keystone.dtsi |   25 +++++++++++++++++++++++++
 2 files changed, 49 insertions(+)

diff --git a/arch/arm/boot/dts/k2e.dtsi b/arch/arm/boot/dts/k2e.dtsi
index 675fb8e..1ba47d8 100644
--- a/arch/arm/boot/dts/k2e.dtsi
+++ b/arch/arm/boot/dts/k2e.dtsi
@@ -86,6 +86,18 @@
 			gpio,syscon-dev = <&devctrl 0x240>;
 		};
 
+		pcie1_phy: pciephy@2326000 {
+			#phy-cells = <0>;
+			compatible = "ti,keystone-serdes-pcie";
+			reg = <0x02326000 0x4000>;
+			reg-names = "reg_serdes";
+			refclk-khz = <100000>;
+			link-rate-kbps = <5000000>;
+			phy-type = "pcie";
+			max-lanes = <2>;
+			status = "disabled";
+		};
+
 		pcie1: pcie@21020000 {
 			compatible = "ti,keystone-pcie","snps,dw-pcie";
 			clocks = <&clkpcie1>;
@@ -130,6 +142,18 @@
 					<GIC_SPI 375 IRQ_TYPE_EDGE_RISING>,
 					<GIC_SPI 376 IRQ_TYPE_EDGE_RISING>;
 			};
+
+			/* PCIE phy */
+			serdeses {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				serdes@0 {
+					reg = <0>;
+					phys = <&pcie1_phy>;
+					status = "disabled";
+				};
+			};
+
 		};
 
 		mdio: mdio@24200f00 {
diff --git a/arch/arm/boot/dts/keystone.dtsi b/arch/arm/boot/dts/keystone.dtsi
index 72816d6..5312319 100644
--- a/arch/arm/boot/dts/keystone.dtsi
+++ b/arch/arm/boot/dts/keystone.dtsi
@@ -275,6 +275,19 @@
 			ti,syscon-dev = <&devctrl 0x2a0>;
 		};
 
+		pcie0_phy: pciephy@2320000 {
+			#phy-cells = <0>;
+			compatible = "ti,keystone-serdes-pcie";
+			reg = <0x02320000 0x4000>;
+			reg-names = "reg_serdes";
+			refclk-khz = <100000>;
+			link-rate-kbps = <5000000>;
+			init-firmware	= "k2_pcie_serdes_init.fw";
+			phy-type = "pcie";
+			max-lanes = <2>;
+			status = "disabled";
+		};
+
 		pcie0: pcie@21800000 {
 			compatible = "ti,keystone-pcie", "snps,dw-pcie";
 			clocks = <&clkpcie>;
@@ -319,6 +332,18 @@
 					<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
 					<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
 			};
+
+			/* PCIE phy */
+			serdeses {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				serdes@0 {
+					reg = <0>;
+					phys = <&pcie0_phy>;
+					status = "disabled";
+				};
+			};
+
 		};
 	};
 };
-- 
1.7.9.5


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

* Re: [PATCH 3/3] ARM: keystone: dts: add PCI serdes driver bindings
  2015-10-13 18:04 ` [PATCH 3/3] ARM: keystone: dts: add PCI serdes driver bindings WingMan Kwok
@ 2015-10-13 18:23   ` Murali Karicheri
  2015-10-13 20:12     ` Kwok, WingMan
  0 siblings, 1 reply; 10+ messages in thread
From: Murali Karicheri @ 2015-10-13 18:23 UTC (permalink / raw)
  To: WingMan Kwok, robh+dt, pawel.moll, mark.rutland, ijc+devicetree,
	galak, kishon, rogerq, bhelgaas, ssantosh, linux, devicetree,
	linux-kernel, linux-pci, linux-arm-kernel

On 10/13/2015 02:04 PM, WingMan Kwok wrote:
> Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
> ---
>   arch/arm/boot/dts/k2e.dtsi      |   24 ++++++++++++++++++++++++
>   arch/arm/boot/dts/keystone.dtsi |   25 +++++++++++++++++++++++++
>   2 files changed, 49 insertions(+)
>
> diff --git a/arch/arm/boot/dts/k2e.dtsi b/arch/arm/boot/dts/k2e.dtsi
> index 675fb8e..1ba47d8 100644
> --- a/arch/arm/boot/dts/k2e.dtsi
> +++ b/arch/arm/boot/dts/k2e.dtsi
> @@ -86,6 +86,18 @@
>   			gpio,syscon-dev = <&devctrl 0x240>;
>   		};
>
> +		pcie1_phy: pciephy@2326000 {
> +			#phy-cells = <0>;
> +			compatible = "ti,keystone-serdes-pcie";
> +			reg = <0x02326000 0x4000>;
> +			reg-names = "reg_serdes";
> +			refclk-khz = <100000>;
> +			link-rate-kbps = <5000000>;
> +			phy-type = "pcie";
> +			max-lanes = <2>;
> +			status = "disabled";
> +		};
> +
>   		pcie1: pcie@21020000 {
>   			compatible = "ti,keystone-pcie","snps,dw-pcie";
>   			clocks = <&clkpcie1>;
> @@ -130,6 +142,18 @@
>   					<GIC_SPI 375 IRQ_TYPE_EDGE_RISING>,
>   					<GIC_SPI 376 IRQ_TYPE_EDGE_RISING>;
>   			};
> +
> +			/* PCIE phy */
> +			serdeses {
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +				serdes@0 {
> +					reg = <0>;
> +					phys = <&pcie1_phy>;
> +					status = "disabled";
> +				};
> +			};
> +
>   		};
>
>   		mdio: mdio@24200f00 {
> diff --git a/arch/arm/boot/dts/keystone.dtsi b/arch/arm/boot/dts/keystone.dtsi
> index 72816d6..5312319 100644
> --- a/arch/arm/boot/dts/keystone.dtsi
> +++ b/arch/arm/boot/dts/keystone.dtsi
> @@ -275,6 +275,19 @@
>   			ti,syscon-dev = <&devctrl 0x2a0>;
>   		};
>
> +		pcie0_phy: pciephy@2320000 {
> +			#phy-cells = <0>;
> +			compatible = "ti,keystone-serdes-pcie";
> +			reg = <0x02320000 0x4000>;
> +			reg-names = "reg_serdes";
> +			refclk-khz = <100000>;
> +			link-rate-kbps = <5000000>;
> +			init-firmware	= "k2_pcie_serdes_init.fw";
> +			phy-type = "pcie";
> +			max-lanes = <2>;
> +			status = "disabled";
> +		};
> +
>   		pcie0: pcie@21800000 {
>   			compatible = "ti,keystone-pcie", "snps,dw-pcie";
>   			clocks = <&clkpcie>;
> @@ -319,6 +332,18 @@
>   					<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
>   					<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
>   			};
> +
> +			/* PCIE phy */
> +			serdeses {
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +				serdes@0 {
> +					reg = <0>;
> +					phys = <&pcie0_phy>;
> +					status = "disabled";
> +				};
> +			};
> +
>   		};
>   	};
>   };
>
Wingman,

This should be a separate patch and remove the sane from Driver patch. 
i.e. send 1/3 ane 2/3 in one series and 3/3 as a separate patch.

Thanks

Murali

-- 
Murali Karicheri
Linux Kernel, Keystone

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

* Re: [PATCH 1/3] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-13 18:04 ` [PATCH 1/3] phy: keystone: serdes driver for gbe 10gbe and pcie WingMan Kwok
@ 2015-10-13 18:33   ` Mark Rutland
  2015-10-13 19:52     ` Kwok, WingMan
  2015-10-13 22:58   ` Kishon Vijay Abraham I
  1 sibling, 1 reply; 10+ messages in thread
From: Mark Rutland @ 2015-10-13 18:33 UTC (permalink / raw)
  To: WingMan Kwok
  Cc: robh+dt, pawel.moll, ijc+devicetree, galak, kishon, rogerq,
	m-karicheri2, bhelgaas, ssantosh, linux, devicetree, linux-kernel,
	linux-pci, linux-arm-kernel

On Tue, Oct 13, 2015 at 02:04:22PM -0400, 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.
> 
> Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
> ---
>  Documentation/devicetree/bindings/phy/ti-phy.txt |  256 +++
>  drivers/phy/Kconfig                              |    8 +
>  drivers/phy/Makefile                             |    1 +
>  drivers/phy/phy-keystone-serdes.c                | 2465 ++++++++++++++++++++++
>  4 files changed, 2730 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..231716e 100644
> --- a/Documentation/devicetree/bindings/phy/ti-phy.txt
> +++ b/Documentation/devicetree/bindings/phy/ti-phy.txt
> @@ -115,4 +115,260 @@ 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:
> +	* "reg_serdes"
> +		- name of the reg SerDes register set

Just describe reg in terms of reg-names, and don't bother with the
"reg_" prefix, we know this is a reg entry:

- reg: a list of address and length pairs, corresponding to entires in
  reg-names

- reg-names: should contain:
  * "serdes"

> + - #phy-cells:
> +	* From the generic phy bindings, must be 0;
> + - max-lanes:
> +	* Number of lanes in SerDes.

Why is this not "num-lanes"? Why do you even need this?

> + - phy-type: should be one of
> +	* "sgmii"
> +	* "xge"
> +	* "pcie"
> +
> +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.
> + - refclk-khz:
> +	* Reference clock rate of SerDes in kHz.

Surely this should be an actual clock?

> + - link-rate-kbps:
> +	* SerDes link rate to be configured, in kbps.

Why does this need to be in the binding? How does one derive the correct
value?

> + - control-rate:
> +	* Lane control rate
> +		0: full rate
> +		1: half rate
> +		2: quarter rate

Likewise on both points.

> + - 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 outpust voltage
> +	  configurations.
> +	* Must be array of 5 integers.

s/outpust/output/

> + - debug:
> +	* enable more debug messages.

NAK.

This is a driver option, and belongs on the kernel command line. It does
not describe the hardware, and does not belong in the DT.

> +Example for Keystone K2E GBE:
> +-----------------------------
> +
> +gbe_serdes0: gbe_serdes@232a000 {
> +	#phy-cells		= <0>;
> +	compatible		= "ti,keystone-serdes-gbe";
> +	reg			= <0x0232a000 0x2000>;
> +	reg-names		= "reg_serdes";
> +	refclk-khz		= <156250>;
> +	link-rate-kbps		= <1250000>;
> +	phy-type		= "sgmii";
> +	max-lanes		= <4>;
> +	lane0 {
> +		control-rate	= <2>; /* quart */
> +		rx-start	= <7 5>;
> +		rx-force	= <1 1>;
> +		tx-coeff	= <0 0 0 12 4>;
> +		       /* c1 c2 cm att vreg */
> +	};
> +	lane1 {
> +		control-rate	= <2>; /* quart */
> +		rx-start	= <7 5>;
> +		rx-force	= <1 1>;
> +		tx-coeff	= <0 0 0 12 4>;
> +		       /* c1 c2 cm att vreg */
> +	};

The binding didn't describe the sub-nodes, and which properties belong
to them.

Don't use magic names. Define a new address space, and use reg to
identify lanes.

> +	if (of_find_property(np, "disable", NULL))
> +		lc->enable = 0;
> +	else
> +		lc->enable = 1;

This was not described in the binding, and uses the wrong accessor. What
is this for?

> +	if (of_find_property(np, "loopback", NULL))
> +		lc->loopback = 1;
> +	else
> +		lc->loopback = 0;

Likewise.

> +	if (of_property_read_bool(np, "syscon-peripheral")) {
> +		sc->peripheral_regmap =
> +			syscon_regmap_lookup_by_phandle(np,
> +							"syscon-peripheral");

Can't you always call syscon_regmap_lookup_by_phandle, then check the
return value to see if the property existed?

You clearly know that of_property_read_bool exists, why did you not use
it to read properties which are boolean?

> +	if (of_property_read_bool(np, "syscon-link")) {
> +		sc->pcsr_regmap =
> +			syscon_regmap_lookup_by_phandle(np, "syscon-link");

Likewise.

> +	sc->debug = of_property_read_bool(np, "debug");

As stated above, NAK for this property.

> +
> +	if (of_find_property(np, "rx-force-enable", NULL))
> +		sc->rx_force_enable = 1;
> +	else
> +		sc->rx_force_enable = 0;

Not in the binding, and uses the wrong accessor.

> +
> +	for (i = 0; i < sc->lanes; i++) {
> +		sprintf(&name[4], "%d", i);
> +		lp = of_find_node_by_name(np, name);
> +		if (lp) {
> +			if (kserdes_get_lane_bindings(dev, lp, &sc->lane[i]))
> +				return -EINVAL;
> +		}
> +	}

As above, use reg, not magic names.

Thanks,
Mark.

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

* RE: [PATCH 1/3] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-13 18:33   ` Mark Rutland
@ 2015-10-13 19:52     ` Kwok, WingMan
  0 siblings, 0 replies; 10+ messages in thread
From: Kwok, WingMan @ 2015-10-13 19:52 UTC (permalink / raw)
  To: Mark Rutland
  Cc: robh+dt@kernel.org, pawel.moll@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, linux-arm-kernel@lists.infradead.org

DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogTWFyayBSdXRsYW5kIFtt
YWlsdG86bWFyay5ydXRsYW5kQGFybS5jb21dDQo+IFNlbnQ6IFR1ZXNkYXksIE9jdG9iZXIgMTMs
IDIwMTUgMjozMyBQTQ0KPiBUbzogS3dvaywgV2luZ01hbg0KPiBDYzogcm9iaCtkdEBrZXJuZWwu
b3JnOyBwYXdlbC5tb2xsQGFybS5jb207DQo+IGlqYytkZXZpY2V0cmVlQGhlbGxpb24ub3JnLnVr
OyBnYWxha0Bjb2RlYXVyb3JhLm9yZzsgS0lTSE9OIFZJSkFZDQo+IEFCUkFIQU07IFF1YWRyb3Ms
IFJvZ2VyOyBLYXJpY2hlcmksIE11cmFsaWRoYXJhbjsgYmhlbGdhYXNAZ29vZ2xlLmNvbTsNCj4g
c3NhbnRvc2hAa2VybmVsLm9yZzsgbGludXhAYXJtLmxpbnV4Lm9yZy51azsNCj4gZGV2aWNldHJl
ZUB2Z2VyLmtlcm5lbC5vcmc7IGxpbnV4LWtlcm5lbEB2Z2VyLmtlcm5lbC5vcmc7IGxpbnV4LQ0K
PiBwY2lAdmdlci5rZXJuZWwub3JnOyBsaW51eC1hcm0ta2VybmVsQGxpc3RzLmluZnJhZGVhZC5v
cmcNCj4gU3ViamVjdDogUmU6IFtQQVRDSCAxLzNdIHBoeToga2V5c3RvbmU6IHNlcmRlcyBkcml2
ZXIgZm9yIGdiZSAxMGdiZQ0KPiBhbmQgcGNpZQ0KPiANCj4gT24gVHVlLCBPY3QgMTMsIDIwMTUg
YXQgMDI6MDQ6MjJQTSAtMDQwMCwgV2luZ01hbiBLd29rIHdyb3RlOg0KPiA+IE9uIFRJJ3MgS2V5
c3RvbmUgcGxhdGZvcm1zLCBzZXZlcmFsIHBlcmlwaGVyYWxzIHN1Y2ggYXMgdGhlDQo+ID4gZ2Jl
IGV0aGVybmV0IHN3aXRjaCwgMTBnYmUgZXRoZXJuZXQgc3dpdGNoIGFuZCBQQ0llIGNvbnRyb2xs
ZXINCj4gPiByZXF1aXJlIHRoZSB1c2Ugb2YgYSBTZXJEZXMgZm9yIGNvbnZlcnRpbmcgU29DIHBh
cmFsbGVsIGRhdGEgaW50bw0KPiA+IHNlcmlhbGl6ZWQgZGF0YSB0aGF0IGNhbiBiZSBvdXRwdXQg
b3ZlciBhIGhpZ2gtc3BlZWQgZWxlY3RyaWNhbA0KPiA+IGludGVyZmFjZSwgYW5kIGFsc28gY29u
dmVydGluZyBoaWdoLXNwZWVkIHNlcmlhbCBpbnB1dCBkYXRhDQo+ID4gaW50byBwYXJhbGxlbCBk
YXRhIHRoYXQgY2FuIGJlIHByb2Nlc3NlZCBieSB0aGUgU29DLiAgVGhlDQo+ID4gU2VyRGVzZXMg
dXNlZCBieSB0aG9zZSBwZXJpcGhlcmFscywgdGhvdWdoIHRoZXkgbWF5IGJlIGRpZmZlcmVudCwN
Cj4gPiBhcmUgbGFyZ2VseSBzaW1pbGFyIGluIGZ1bmN0aW9uYWxpdHkgYW5kIHNldHVwLg0KPiA+
DQo+ID4gVGhpcyBwYXRjaCBwcm92aWRlcyBhIFNlckRlcyBwaHkgZHJpdmVyIGltcGxlbWVudGF0
aW9uIHRoYXQgY2FuIGJlDQo+ID4gdXNlZCBieSB0aGUgYWJvdmUgbWVudGlvbmVkIHBlcmlwaGVy
YWwgZHJpdmVycyB0byBjb25maWd1cmUgdGhlaXINCj4gPiByZXNwZWN0aXZlIFNlckRlc2VzLg0K
PiA+DQo+ID4gU2lnbmVkLW9mZi1ieTogV2luZ01hbiBLd29rIDx3LWt3b2syQHRpLmNvbT4NCj4g
PiAtLS0NCj4gPiAgRG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdzL3BoeS90aS1waHku
dHh0IHwgIDI1NiArKysNCj4gPiAgZHJpdmVycy9waHkvS2NvbmZpZyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIHwgICAgOCArDQo+ID4gIGRyaXZlcnMvcGh5L01ha2VmaWxlICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICB8ICAgIDEgKw0KPiA+ICBkcml2ZXJzL3BoeS9waHkta2V5c3Rv
bmUtc2VyZGVzLmMgICAgICAgICAgICAgICAgfCAyNDY1DQo+ICsrKysrKysrKysrKysrKysrKysr
KysNCj4gPiAgNCBmaWxlcyBjaGFuZ2VkLCAyNzMwIGluc2VydGlvbnMoKykNCj4gPiAgY3JlYXRl
IG1vZGUgMTAwNjQ0IGRyaXZlcnMvcGh5L3BoeS1rZXlzdG9uZS1zZXJkZXMuYw0KPiA+DQo+ID4g
ZGlmZiAtLWdpdCBhL0RvY3VtZW50YXRpb24vZGV2aWNldHJlZS9iaW5kaW5ncy9waHkvdGktcGh5
LnR4dA0KPiBiL0RvY3VtZW50YXRpb24vZGV2aWNldHJlZS9iaW5kaW5ncy9waHkvdGktcGh5LnR4
dA0KPiA+IGluZGV4IDljZjk0NDYuLjIzMTcxNmUgMTAwNjQ0DQo+ID4gLS0tIGEvRG9jdW1lbnRh
dGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdzL3BoeS90aS1waHkudHh0DQo+ID4gKysrIGIvRG9jdW1l
bnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdzL3BoeS90aS1waHkudHh0DQo+ID4gQEAgLTExNSw0
ICsxMTUsMjYwIEBAIHNhdGFfcGh5OiBwaHlANEEwOTYwMDAgew0KPiA+ICAJY2xvY2stbmFtZXMg
PSAic3lzY2xrIiwgInJlZmNsayI7DQo+ID4gIAlzeXNjb24tcGxscmVzZXQgPSA8JnNjbV9jb25m
IDB4M2ZjPjsNCj4gPiAgCSNwaHktY2VsbHMgPSA8MD47DQo+ID4gKw0KPiA+ICtUSSBLZXlzdG9u
ZSBTZXJEZXMgUEhZDQo+ID4gKz09PT09PT09PT09PT09PT09PT09PT0NCj4gPiArDQo+ID4gK1Jl
cXVpcmVkIHByb3BlcnRpZXM6DQo+ID4gKyAtIGNvbXBhdGlibGU6IHNob3VsZCBiZSBvbmUgb2YN
Cj4gPiArCSogInRpLGtleXN0b25lLXNlcmRlcy1nYmUiDQo+ID4gKwkqICJ0aSxrZXlzdG9uZS1z
ZXJkZXMteGdiZSINCj4gPiArCSogInRpLGtleXN0b25lLXNlcmRlcy1wY2llIg0KPiA+ICsgLSBy
ZWc6DQo+ID4gKwkqIGJhc2UgYWRkcmVzcyBhbmQgbGVuZ3RoIG9mIHRoZSBTZXJEZXMgcmVnaXN0
ZXIgc2V0DQo+ID4gKyAtIHJlZy1uYW1lczoNCj4gPiArCSogInJlZ19zZXJkZXMiDQo+ID4gKwkJ
LSBuYW1lIG9mIHRoZSByZWcgU2VyRGVzIHJlZ2lzdGVyIHNldA0KPiANCj4gSnVzdCBkZXNjcmli
ZSByZWcgaW4gdGVybXMgb2YgcmVnLW5hbWVzLCBhbmQgZG9uJ3QgYm90aGVyIHdpdGggdGhlDQo+
ICJyZWdfIiBwcmVmaXgsIHdlIGtub3cgdGhpcyBpcyBhIHJlZyBlbnRyeToNCj4gDQo+IC0gcmVn
OiBhIGxpc3Qgb2YgYWRkcmVzcyBhbmQgbGVuZ3RoIHBhaXJzLCBjb3JyZXNwb25kaW5nIHRvIGVu
dGlyZXMgaW4NCj4gICByZWctbmFtZXMNCj4gDQo+IC0gcmVnLW5hbWVzOiBzaG91bGQgY29udGFp
bjoNCj4gICAqICJzZXJkZXMiDQo+IA0KPiA+ICsgLSAjcGh5LWNlbGxzOg0KPiA+ICsJKiBGcm9t
IHRoZSBnZW5lcmljIHBoeSBiaW5kaW5ncywgbXVzdCBiZSAwOw0KPiA+ICsgLSBtYXgtbGFuZXM6
DQo+ID4gKwkqIE51bWJlciBvZiBsYW5lcyBpbiBTZXJEZXMuDQo+IA0KPiBXaHkgaXMgdGhpcyBu
b3QgIm51bS1sYW5lcyI/IFdoeSBkbyB5b3UgZXZlbiBuZWVkIHRoaXM/DQo+IA0KDQp3aWxsIGNo
YW5nZSB0byAibnVtLWxhbmVzIi4NCg0Kc2VyZGVzIG9uIGRpZmZlcmVudCBwZXJpcGhlcmFscyBo
YXZlIGRpZmZlcmVudCBudW1iZXIgb2YNCmxhbmVzIGFuZCBlYWNoIGluZGl2aWR1YWwgbGFuZSBj
YW4gYmUgZW5hYmxlZCBvciBkaXNhYmxlZC4NCg0KPiA+ICsgLSBwaHktdHlwZTogc2hvdWxkIGJl
IG9uZSBvZg0KPiA+ICsJKiAic2dtaWkiDQo+ID4gKwkqICJ4Z2UiDQo+ID4gKwkqICJwY2llIg0K
PiA+ICsNCj4gPiArT3B0aW9uYWwgcHJvcGVydGllczoNCj4gPiArIC0gc3lzY29uLXBlcmlwaGVy
YWw6DQo+ID4gKwkqIEhhbmRsZSB0byB0aGUgc3Vic3lzdGVtIHJlZ2lzdGVyIHJlZ2lvbiBvZiB0
aGUgcGVyaXBoZXJhbA0KPiA+ICsJICBpbnNpZGUgd2hpY2ggdGhlIFNlckRlcyBleGlzdHMuDQo+
ID4gKyAtIHN5c2Nvbi1saW5rOg0KPiA+ICsJKiBIYW5kbGUgdG8gdGhlIExpbmsgcmVnaXN0ZXIg
cmVnaW9uIG9mIHRoZSBwZXJpcGhlcmFsIGluc2lkZQ0KPiA+ICsJICB3aGljaCB0aGUgU2VyRGVz
IGV4aXN0cy4gIEV4YW1wbGU6IGl0IGlzIHRoZSBQQ1NSIHJlZ2lzdGVyDQo+ID4gKwkgIHJlZ2lv
biBpbiB0aGUgY2FzZSBvZiAxMGdiZS4NCj4gPiArIC0gcmVmY2xrLWtoejoNCj4gPiArCSogUmVm
ZXJlbmNlIGNsb2NrIHJhdGUgb2YgU2VyRGVzIGluIGtIei4NCj4gDQo+IFN1cmVseSB0aGlzIHNo
b3VsZCBiZSBhbiBhY3R1YWwgY2xvY2s/DQo+IA0KDQpvaywgdGhpcyBpcyBub3QgYWN0dWFsbHkg
bmVlZGVkIGFuZCB3aWxsIHJlbW92ZQ0KDQo+ID4gKyAtIGxpbmstcmF0ZS1rYnBzOg0KPiA+ICsJ
KiBTZXJEZXMgbGluayByYXRlIHRvIGJlIGNvbmZpZ3VyZWQsIGluIGticHMuDQo+IA0KPiBXaHkg
ZG9lcyB0aGlzIG5lZWQgdG8gYmUgaW4gdGhlIGJpbmRpbmc/IEhvdyBkb2VzIG9uZSBkZXJpdmUg
dGhlDQo+IGNvcnJlY3QNCj4gdmFsdWU/DQo+IA0KDQphIHNlcmRlcyBjYW4gYmUgY29uZmlndXJl
ZCBhdCBkaWZmZXJlbnQgbGluayByYXRlcy4gIGZvciBleGFtcGxlLA0KdGhlIDEwZ2JlIHNlcmRl
cyBjYW4gYmUgY29uZmlndXJlZCBhdCAxLjI1RyBsaW5rIHJhdGUgdG8gc3VwcG9ydA0KMWdiZSBv
biB0aGUgMTBnYmUgc3dpdGNoLg0KDQo+ID4gKyAtIGNvbnRyb2wtcmF0ZToNCj4gPiArCSogTGFu
ZSBjb250cm9sIHJhdGUNCj4gPiArCQkwOiBmdWxsIHJhdGUNCj4gPiArCQkxOiBoYWxmIHJhdGUN
Cj4gPiArCQkyOiBxdWFydGVyIHJhdGUNCj4gDQo+IExpa2V3aXNlIG9uIGJvdGggcG9pbnRzLg0K
DQp0aGUgc2VyZGVzIGlzIGEgZ2VuZXJpYyBoYXJkd2FyZSBibG9jayB0aGF0IG5lZWRzIHRvIGJl
IGNvbmZpZ3VyZWQNCndpdGggdGhlIHByb3BlciBsaW5rLXJhdGUgYW5kIGxhbmUgY29udHJvbCBy
YXRlLg0KDQo+IA0KPiA+ICsgLSByeC1zdGFydDoNCj4gPiArCSogSW5pdGlhbCBsYW5lIHJ4IGVx
dWFsaXplciBhdHRlbnVhdGlvbiBhbmQgYm9vc3QgY29uZmlndXJhdGlvbnMuDQo+ID4gKwkqIE11
c3QgYmUgYXJyYXkgb2YgMiBpbnRlZ2Vycy4NCj4gPiArIC0gcngtZm9yY2U6DQo+ID4gKwkqIEZv
cmNlZCBsYW5lIHJ4IGVxdWFsaXplciBhdHRlbnVhdGlvbiBhbmQgYm9vc3QgY29uZmlndXJhdGlv
bnMuDQo+ID4gKwkqIE11c3QgYmUgYXJyYXkgb2YgMiBpbnRlZ2Vycy4NCj4gPiArIC0gdHgtY29l
ZmY6DQo+ID4gKwkqIExhbmUgYzEsIGMyLCBjbSwgYXR0ZW51YXRpb24gYW5kIHJlZ3VsYXRvciBv
dXRwdXN0IHZvbHRhZ2UNCj4gPiArCSAgY29uZmlndXJhdGlvbnMuDQo+ID4gKwkqIE11c3QgYmUg
YXJyYXkgb2YgNSBpbnRlZ2Vycy4NCj4gDQo+IHMvb3V0cHVzdC9vdXRwdXQvDQo+IA0KDQpvay4N
Cg0KPiA+ICsgLSBkZWJ1ZzoNCj4gPiArCSogZW5hYmxlIG1vcmUgZGVidWcgbWVzc2FnZXMuDQo+
IA0KPiBOQUsuDQo+IA0KPiBUaGlzIGlzIGEgZHJpdmVyIG9wdGlvbiwgYW5kIGJlbG9uZ3Mgb24g
dGhlIGtlcm5lbCBjb21tYW5kIGxpbmUuIEl0DQo+IGRvZXMNCj4gbm90IGRlc2NyaWJlIHRoZSBo
YXJkd2FyZSwgYW5kIGRvZXMgbm90IGJlbG9uZyBpbiB0aGUgRFQuDQo+IA0KDQp3aWxsIHJlbW92
ZS4NCg0KPiA+ICtFeGFtcGxlIGZvciBLZXlzdG9uZSBLMkUgR0JFOg0KPiA+ICstLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLQ0KPiA+ICsNCj4gPiArZ2JlX3NlcmRlczA6IGdiZV9zZXJkZXNA
MjMyYTAwMCB7DQo+ID4gKwkjcGh5LWNlbGxzCQk9IDwwPjsNCj4gPiArCWNvbXBhdGlibGUJCT0g
InRpLGtleXN0b25lLXNlcmRlcy1nYmUiOw0KPiA+ICsJcmVnCQkJPSA8MHgwMjMyYTAwMCAweDIw
MDA+Ow0KPiA+ICsJcmVnLW5hbWVzCQk9ICJyZWdfc2VyZGVzIjsNCj4gPiArCXJlZmNsay1raHoJ
CT0gPDE1NjI1MD47DQo+ID4gKwlsaW5rLXJhdGUta2JwcwkJPSA8MTI1MDAwMD47DQo+ID4gKwlw
aHktdHlwZQkJPSAic2dtaWkiOw0KPiA+ICsJbWF4LWxhbmVzCQk9IDw0PjsNCj4gPiArCWxhbmUw
IHsNCj4gPiArCQljb250cm9sLXJhdGUJPSA8Mj47IC8qIHF1YXJ0ICovDQo+ID4gKwkJcngtc3Rh
cnQJPSA8NyA1PjsNCj4gPiArCQlyeC1mb3JjZQk9IDwxIDE+Ow0KPiA+ICsJCXR4LWNvZWZmCT0g
PDAgMCAwIDEyIDQ+Ow0KPiA+ICsJCSAgICAgICAvKiBjMSBjMiBjbSBhdHQgdnJlZyAqLw0KPiA+
ICsJfTsNCj4gPiArCWxhbmUxIHsNCj4gPiArCQljb250cm9sLXJhdGUJPSA8Mj47IC8qIHF1YXJ0
ICovDQo+ID4gKwkJcngtc3RhcnQJPSA8NyA1PjsNCj4gPiArCQlyeC1mb3JjZQk9IDwxIDE+Ow0K
PiA+ICsJCXR4LWNvZWZmCT0gPDAgMCAwIDEyIDQ+Ow0KPiA+ICsJCSAgICAgICAvKiBjMSBjMiBj
bSBhdHQgdnJlZyAqLw0KPiA+ICsJfTsNCj4gDQo+IFRoZSBiaW5kaW5nIGRpZG4ndCBkZXNjcmli
ZSB0aGUgc3ViLW5vZGVzLCBhbmQgd2hpY2ggcHJvcGVydGllcyBiZWxvbmcNCj4gdG8gdGhlbS4N
Cj4gDQoNCndpbGwgYWRkIGRlc2NyaXB0aW9ucyBmb3IgbGFuZSBub2Rlcw0KDQo+IERvbid0IHVz
ZSBtYWdpYyBuYW1lcy4gRGVmaW5lIGEgbmV3IGFkZHJlc3Mgc3BhY2UsIGFuZCB1c2UgcmVnIHRv
DQo+IGlkZW50aWZ5IGxhbmVzLg0KPiANCg0Kd2lsbCB1cGRhdGUgdG8gdGhlIGZvbGxvd2luZw0K
DQpsYW5lcyB7DQoJbGFuZUAwIHsNCgkJcmVnID0gPDA+Ow0KCQkuLi4NCgl9Ow0KDQoJbGFuZUAx
IHsNCgkJcmVnID0gPDE+Ow0KCQkuLi4JDQoJfTsNCn07DQoNCg0KPiA+ICsJaWYgKG9mX2ZpbmRf
cHJvcGVydHkobnAsICJkaXNhYmxlIiwgTlVMTCkpDQo+ID4gKwkJbGMtPmVuYWJsZSA9IDA7DQo+
ID4gKwllbHNlDQo+ID4gKwkJbGMtPmVuYWJsZSA9IDE7DQo+IA0KPiBUaGlzIHdhcyBub3QgZGVz
Y3JpYmVkIGluIHRoZSBiaW5kaW5nLCBhbmQgdXNlcyB0aGUgd3JvbmcgYWNjZXNzb3IuDQo+IFdo
YXQNCj4gaXMgdGhpcyBmb3I/DQoNCmFmdGVyIHRoZSBhYm92ZSBtZW50aW9uZWQgdXBkYXRlLCB0
aGlzIHdpbGwgYmVjb21lOiBzdGF0dXMgPSAiZGlzYWJsZWQvb2siLg0KPiANCj4gPiArCWlmIChv
Zl9maW5kX3Byb3BlcnR5KG5wLCAibG9vcGJhY2siLCBOVUxMKSkNCj4gPiArCQlsYy0+bG9vcGJh
Y2sgPSAxOw0KPiA+ICsJZWxzZQ0KPiA+ICsJCWxjLT5sb29wYmFjayA9IDA7DQo+IA0KPiBMaWtl
d2lzZS4NCg0Kd2lsbCBhZGQgZG9jdW1lbnRhdGlvbg0KDQo+IA0KPiA+ICsJaWYgKG9mX3Byb3Bl
cnR5X3JlYWRfYm9vbChucCwgInN5c2Nvbi1wZXJpcGhlcmFsIikpIHsNCj4gPiArCQlzYy0+cGVy
aXBoZXJhbF9yZWdtYXAgPQ0KPiA+ICsJCQlzeXNjb25fcmVnbWFwX2xvb2t1cF9ieV9waGFuZGxl
KG5wLA0KPiA+ICsJCQkJCQkJInN5c2Nvbi1wZXJpcGhlcmFsIik7DQo+IA0KPiBDYW4ndCB5b3Ug
YWx3YXlzIGNhbGwgc3lzY29uX3JlZ21hcF9sb29rdXBfYnlfcGhhbmRsZSwgdGhlbiBjaGVjayB0
aGUNCj4gcmV0dXJuIHZhbHVlIHRvIHNlZSBpZiB0aGUgcHJvcGVydHkgZXhpc3RlZD8NCj4gDQo+
IFlvdSBjbGVhcmx5IGtub3cgdGhhdCBvZl9wcm9wZXJ0eV9yZWFkX2Jvb2wgZXhpc3RzLCB3aHkg
ZGlkIHlvdSBub3QNCj4gdXNlDQo+IGl0IHRvIHJlYWQgcHJvcGVydGllcyB3aGljaCBhcmUgYm9v
bGVhbj8NCj4gDQoNCm9rLg0KDQo+ID4gKwlpZiAob2ZfcHJvcGVydHlfcmVhZF9ib29sKG5wLCAi
c3lzY29uLWxpbmsiKSkgew0KPiA+ICsJCXNjLT5wY3NyX3JlZ21hcCA9DQo+ID4gKwkJCXN5c2Nv
bl9yZWdtYXBfbG9va3VwX2J5X3BoYW5kbGUobnAsICJzeXNjb24tbGluayIpOw0KPiANCj4gTGlr
ZXdpc2UuDQo+IA0KDQpvay4NCg0KPiA+ICsJc2MtPmRlYnVnID0gb2ZfcHJvcGVydHlfcmVhZF9i
b29sKG5wLCAiZGVidWciKTsNCj4gDQo+IEFzIHN0YXRlZCBhYm92ZSwgTkFLIGZvciB0aGlzIHBy
b3BlcnR5Lg0KPiANCiANCndpbGwgcmVtb3ZlLg0KDQo+ID4gKw0KPiA+ICsJaWYgKG9mX2ZpbmRf
cHJvcGVydHkobnAsICJyeC1mb3JjZS1lbmFibGUiLCBOVUxMKSkNCj4gPiArCQlzYy0+cnhfZm9y
Y2VfZW5hYmxlID0gMTsNCj4gPiArCWVsc2UJDQo+ID4gKwkJc2MtPnJ4X2ZvcmNlX2VuYWJsZSA9
IDA7DQo+IA0KPiBOb3QgaW4gdGhlIGJpbmRpbmcsIGFuZCB1c2VzIHRoZSB3cm9uZyBhY2Nlc3Nv
ci4NCj4gDQoNCm9rLiB3aWxsIHVwZGF0ZSB0aGUgYmluZGluZyBhbmQgY2hhbmdlIG9mX2ZpbmRf
cHJvcGVydHkgdG8NCm9mX3Byb3BlcnR5X3JlYWRfYm9vbC4NCg0KPiA+ICsNCj4gPiArCWZvciAo
aSA9IDA7IGkgPCBzYy0+bGFuZXM7IGkrKykgew0KPiA+ICsJCXNwcmludGYoJm5hbWVbNF0sICIl
ZCIsIGkpOw0KPiA+ICsJCWxwID0gb2ZfZmluZF9ub2RlX2J5X25hbWUobnAsIG5hbWUpOw0KPiA+
ICsJCWlmIChscCkgew0KPiA+ICsJCQlpZiAoa3NlcmRlc19nZXRfbGFuZV9iaW5kaW5ncyhkZXYs
IGxwLCAmc2MtPmxhbmVbaV0pKQ0KPiA+ICsJCQkJcmV0dXJuIC1FSU5WQUw7DQo+ID4gKwkJfQ0K
PiA+ICsJfQ0KPiANCj4gQXMgYWJvdmUsIHVzZSByZWcsIG5vdCBtYWdpYyBuYW1lcy4NCg0Kb2su
DQoNClRoYW5rcywNCldpbmdNYW4NCg==

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

* RE: [PATCH 3/3] ARM: keystone: dts: add PCI serdes driver bindings
  2015-10-13 18:23   ` Murali Karicheri
@ 2015-10-13 20:12     ` Kwok, WingMan
  0 siblings, 0 replies; 10+ messages in thread
From: Kwok, WingMan @ 2015-10-13 20:12 UTC (permalink / raw)
  To: Karicheri, Muralidharan, 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, linux-arm-kernel@lists.infradead.org

DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogS2FyaWNoZXJpLCBNdXJh
bGlkaGFyYW4NCj4gU2VudDogVHVlc2RheSwgT2N0b2JlciAxMywgMjAxNSAyOjI0IFBNDQo+IFRv
OiBLd29rLCBXaW5nTWFuOyByb2JoK2R0QGtlcm5lbC5vcmc7IHBhd2VsLm1vbGxAYXJtLmNvbTsN
Cj4gbWFyay5ydXRsYW5kQGFybS5jb207IGlqYytkZXZpY2V0cmVlQGhlbGxpb24ub3JnLnVrOyBn
YWxha0Bjb2RlYXVyb3JhLm9yZzsNCj4gS0lTSE9OIFZJSkFZIEFCUkFIQU07IFF1YWRyb3MsIFJv
Z2VyOyBiaGVsZ2Fhc0Bnb29nbGUuY29tOw0KPiBzc2FudG9zaEBrZXJuZWwub3JnOyBsaW51eEBh
cm0ubGludXgub3JnLnVrOyBkZXZpY2V0cmVlQHZnZXIua2VybmVsLm9yZzsNCj4gbGludXgta2Vy
bmVsQHZnZXIua2VybmVsLm9yZzsgbGludXgtcGNpQHZnZXIua2VybmVsLm9yZzsgbGludXgtYXJt
LQ0KPiBrZXJuZWxAbGlzdHMuaW5mcmFkZWFkLm9yZw0KPiBTdWJqZWN0OiBSZTogW1BBVENIIDMv
M10gQVJNOiBrZXlzdG9uZTogZHRzOiBhZGQgUENJIHNlcmRlcyBkcml2ZXIgYmluZGluZ3MNCj4g
DQo+IE9uIDEwLzEzLzIwMTUgMDI6MDQgUE0sIFdpbmdNYW4gS3dvayB3cm90ZToNCj4gPiBTaWdu
ZWQtb2ZmLWJ5OiBXaW5nTWFuIEt3b2sgPHcta3dvazJAdGkuY29tPg0KPiA+IC0tLQ0KPiA+ICAg
YXJjaC9hcm0vYm9vdC9kdHMvazJlLmR0c2kgICAgICB8ICAgMjQgKysrKysrKysrKysrKysrKysr
KysrKysrDQo+ID4gICBhcmNoL2FybS9ib290L2R0cy9rZXlzdG9uZS5kdHNpIHwgICAyNSArKysr
KysrKysrKysrKysrKysrKysrKysrDQo+ID4gICAyIGZpbGVzIGNoYW5nZWQsIDQ5IGluc2VydGlv
bnMoKykNCj4gPg0KPiA+IGRpZmYgLS1naXQgYS9hcmNoL2FybS9ib290L2R0cy9rMmUuZHRzaSBi
L2FyY2gvYXJtL2Jvb3QvZHRzL2syZS5kdHNpDQo+ID4gaW5kZXggNjc1ZmI4ZS4uMWJhNDdkOCAx
MDA2NDQNCj4gPiAtLS0gYS9hcmNoL2FybS9ib290L2R0cy9rMmUuZHRzaQ0KPiA+ICsrKyBiL2Fy
Y2gvYXJtL2Jvb3QvZHRzL2syZS5kdHNpDQo+ID4gQEAgLTg2LDYgKzg2LDE4IEBADQo+ID4gICAJ
CQlncGlvLHN5c2Nvbi1kZXYgPSA8JmRldmN0cmwgMHgyNDA+Ow0KPiA+ICAgCQl9Ow0KPiA+DQo+
ID4gKwkJcGNpZTFfcGh5OiBwY2llcGh5QDIzMjYwMDAgew0KPiA+ICsJCQkjcGh5LWNlbGxzID0g
PDA+Ow0KPiA+ICsJCQljb21wYXRpYmxlID0gInRpLGtleXN0b25lLXNlcmRlcy1wY2llIjsNCj4g
PiArCQkJcmVnID0gPDB4MDIzMjYwMDAgMHg0MDAwPjsNCj4gPiArCQkJcmVnLW5hbWVzID0gInJl
Z19zZXJkZXMiOw0KPiA+ICsJCQlyZWZjbGsta2h6ID0gPDEwMDAwMD47DQo+ID4gKwkJCWxpbmst
cmF0ZS1rYnBzID0gPDUwMDAwMDA+Ow0KPiA+ICsJCQlwaHktdHlwZSA9ICJwY2llIjsNCj4gPiAr
CQkJbWF4LWxhbmVzID0gPDI+Ow0KPiA+ICsJCQlzdGF0dXMgPSAiZGlzYWJsZWQiOw0KPiA+ICsJ
CX07DQo+ID4gKw0KPiA+ICAgCQlwY2llMTogcGNpZUAyMTAyMDAwMCB7DQo+ID4gICAJCQljb21w
YXRpYmxlID0gInRpLGtleXN0b25lLXBjaWUiLCJzbnBzLGR3LXBjaWUiOw0KPiA+ICAgCQkJY2xv
Y2tzID0gPCZjbGtwY2llMT47DQo+ID4gQEAgLTEzMCw2ICsxNDIsMTggQEANCj4gPiAgIAkJCQkJ
PEdJQ19TUEkgMzc1IElSUV9UWVBFX0VER0VfUklTSU5HPiwNCj4gPiAgIAkJCQkJPEdJQ19TUEkg
Mzc2IElSUV9UWVBFX0VER0VfUklTSU5HPjsNCj4gPiAgIAkJCX07DQo+ID4gKw0KPiA+ICsJCQkv
KiBQQ0lFIHBoeSAqLw0KPiA+ICsJCQlzZXJkZXNlcyB7DQo+ID4gKwkJCQkjYWRkcmVzcy1jZWxs
cyA9IDwxPjsNCj4gPiArCQkJCSNzaXplLWNlbGxzID0gPDA+Ow0KPiA+ICsJCQkJc2VyZGVzQDAg
ew0KPiA+ICsJCQkJCXJlZyA9IDwwPjsNCj4gPiArCQkJCQlwaHlzID0gPCZwY2llMV9waHk+Ow0K
PiA+ICsJCQkJCXN0YXR1cyA9ICJkaXNhYmxlZCI7DQo+ID4gKwkJCQl9Ow0KPiA+ICsJCQl9Ow0K
PiA+ICsNCj4gPiAgIAkJfTsNCj4gPg0KPiA+ICAgCQltZGlvOiBtZGlvQDI0MjAwZjAwIHsNCj4g
PiBkaWZmIC0tZ2l0IGEvYXJjaC9hcm0vYm9vdC9kdHMva2V5c3RvbmUuZHRzaQ0KPiBiL2FyY2gv
YXJtL2Jvb3QvZHRzL2tleXN0b25lLmR0c2kNCj4gPiBpbmRleCA3MjgxNmQ2Li41MzEyMzE5IDEw
MDY0NA0KPiA+IC0tLSBhL2FyY2gvYXJtL2Jvb3QvZHRzL2tleXN0b25lLmR0c2kNCj4gPiArKysg
Yi9hcmNoL2FybS9ib290L2R0cy9rZXlzdG9uZS5kdHNpDQo+ID4gQEAgLTI3NSw2ICsyNzUsMTkg
QEANCj4gPiAgIAkJCXRpLHN5c2Nvbi1kZXYgPSA8JmRldmN0cmwgMHgyYTA+Ow0KPiA+ICAgCQl9
Ow0KPiA+DQo+ID4gKwkJcGNpZTBfcGh5OiBwY2llcGh5QDIzMjAwMDAgew0KPiA+ICsJCQkjcGh5
LWNlbGxzID0gPDA+Ow0KPiA+ICsJCQljb21wYXRpYmxlID0gInRpLGtleXN0b25lLXNlcmRlcy1w
Y2llIjsNCj4gPiArCQkJcmVnID0gPDB4MDIzMjAwMDAgMHg0MDAwPjsNCj4gPiArCQkJcmVnLW5h
bWVzID0gInJlZ19zZXJkZXMiOw0KPiA+ICsJCQlyZWZjbGsta2h6ID0gPDEwMDAwMD47DQo+ID4g
KwkJCWxpbmstcmF0ZS1rYnBzID0gPDUwMDAwMDA+Ow0KPiA+ICsJCQlpbml0LWZpcm13YXJlCT0g
ImsyX3BjaWVfc2VyZGVzX2luaXQuZnciOw0KPiA+ICsJCQlwaHktdHlwZSA9ICJwY2llIjsNCj4g
PiArCQkJbWF4LWxhbmVzID0gPDI+Ow0KPiA+ICsJCQlzdGF0dXMgPSAiZGlzYWJsZWQiOw0KPiA+
ICsJCX07DQo+ID4gKw0KPiA+ICAgCQlwY2llMDogcGNpZUAyMTgwMDAwMCB7DQo+ID4gICAJCQlj
b21wYXRpYmxlID0gInRpLGtleXN0b25lLXBjaWUiLCAic25wcyxkdy1wY2llIjsNCj4gPiAgIAkJ
CWNsb2NrcyA9IDwmY2xrcGNpZT47DQo+ID4gQEAgLTMxOSw2ICszMzIsMTggQEANCj4gPiAgIAkJ
CQkJPEdJQ19TUEkgMjggSVJRX1RZUEVfRURHRV9SSVNJTkc+LA0KPiA+ICAgCQkJCQk8R0lDX1NQ
SSAyOSBJUlFfVFlQRV9FREdFX1JJU0lORz47DQo+ID4gICAJCQl9Ow0KPiA+ICsNCj4gPiArCQkJ
LyogUENJRSBwaHkgKi8NCj4gPiArCQkJc2VyZGVzZXMgew0KPiA+ICsJCQkJI2FkZHJlc3MtY2Vs
bHMgPSA8MT47DQo+ID4gKwkJCQkjc2l6ZS1jZWxscyA9IDwwPjsNCj4gPiArCQkJCXNlcmRlc0Aw
IHsNCj4gPiArCQkJCQlyZWcgPSA8MD47DQo+ID4gKwkJCQkJcGh5cyA9IDwmcGNpZTBfcGh5PjsN
Cj4gPiArCQkJCQlzdGF0dXMgPSAiZGlzYWJsZWQiOw0KPiA+ICsJCQkJfTsNCj4gPiArCQkJfTsN
Cj4gPiArDQo+ID4gICAJCX07DQo+ID4gICAJfTsNCj4gPiAgIH07DQo+ID4NCj4gV2luZ21hbiwN
Cj4gDQo+IFRoaXMgc2hvdWxkIGJlIGEgc2VwYXJhdGUgcGF0Y2ggYW5kIHJlbW92ZSB0aGUgc2Fu
ZSBmcm9tIERyaXZlciBwYXRjaC4NCj4gaS5lLiBzZW5kIDEvMyBhbmUgMi8zIGluIG9uZSBzZXJp
ZXMgYW5kIDMvMyBhcyBhIHNlcGFyYXRlIHBhdGNoLg0KPiANCg0Kd2lsbCBkby4NCg0KVGhhbmtz
LA0Kd2luZ01hbg0K

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

* Re: [PATCH 1/3] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-13 18:04 ` [PATCH 1/3] phy: keystone: serdes driver for gbe 10gbe and pcie WingMan Kwok
  2015-10-13 18:33   ` Mark Rutland
@ 2015-10-13 22:58   ` Kishon Vijay Abraham I
  2015-10-14 15:15     ` Kwok, WingMan
  1 sibling, 1 reply; 10+ messages in thread
From: Kishon Vijay Abraham I @ 2015-10-13 22:58 UTC (permalink / raw)
  To: WingMan Kwok, robh+dt, pawel.moll, mark.rutland, ijc+devicetree,
	galak, rogerq, m-karicheri2, bhelgaas, ssantosh, linux,
	devicetree, linux-kernel, linux-pci, linux-arm-kernel

Hi,

On Tuesday 13 October 2015 11:34 PM, 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.
> 
> Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
> ---
>  Documentation/devicetree/bindings/phy/ti-phy.txt |  256 +++
>  drivers/phy/Kconfig                              |    8 +
>  drivers/phy/Makefile                             |    1 +
>  drivers/phy/phy-keystone-serdes.c                | 2465 ++++++++++++++++++++++
>  4 files changed, 2730 insertions(+)
>  create mode 100644 drivers/phy/phy-keystone-serdes.c
> 

<snip>

> 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..c73d4de
> --- /dev/null
> +++ b/drivers/phy/phy-keystone-serdes.c
> @@ -0,0 +1,2465 @@
> +/*
> + * 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))
> +
> +/* bit mask from bit-a to bit-b inclusive */
> +#define MASK(msb, lsb) \
> +	((((msb) - (lsb)) == 31) ? 0xffffffff :  \
> +		((((u32)1 << ((msb) - (lsb) + 1)) - 1) << (lsb)))

use GENMASK instead?
> +
> +/* 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)), MASK((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 for_each_lane_return(func, sc, r)		\
> +	do {						\
> +		int i;					\
> +		(r) = 0;				\
> +		for (i = 0; i < (sc)->lanes; i++) {	\
> +			(r) = (func)((sc), i);		\
> +			if ((r))			\
> +				break;			\
> +		}					\
> +	} while (0)

Overuse of macros here and *for_each_lane_return* is not used in this
file at all.
> +
> +#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	MASK(21, 20)
> +#define ANEG_LINK_CTL_1GKX_MASK		MASK(17, 16)
> +#define ANEG_LINK_CTL_1G10G_MASK \
> +	(ANEG_LINK_CTL_10GKR_MASK | ANEG_LINK_CTL_1GKX_MASK)
> +

<snip>

> +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 64B data mem */
> +	kserdes_writel(sc->regs, MEM_ADR_REG, 0x0000ffc0);
> +
> +	for (i = 0; i < 11; i++)

Why 11? This needs a macro.
> +		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)
> +{
> +	if (sc->clk_rate != KSERDES_CLOCK_RATE_156P25M)
> +		return -EINVAL;
> +
> +	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)
> +{
> +	if ((sc->clk_rate != KSERDES_CLOCK_RATE_100M) ||
> +	    (sc->link_rate != KSERDES_LINK_RATE_5G))
> +		return -EINVAL;
> +
> +	return kserdes_load_init_fw(sc, ks2_pcie_serdes_firmwares,
> +				    ARRAY_SIZE(ks2_pcie_serdes_firmwares));
> +}
> +
> +static void kserdes_show_fw_config(struct kserdes_config *sc)
> +{
> +	struct kserdes_fw_config *fw = &sc->fw;
> +
> +	dev_info(sc->dev, "fw configs:\n");
> +	dev_info(sc->dev, "  lane_configs: 0x%02x, 0x%02x\n",
> +		 fw->lane_config[0], fw->lane_config[1]);
> +	dev_info(sc->dev,
> +		 "  lnk_loss_wait: %d, lane_seeds: 0x%08x, fast_train: 0x%08x\n",
> +		 fw->link_loss_wait, fw->lane_seeds, fw->fast_train);

This looks more like a debug feature. Lets use debugfs for it.
> +}
> +
> +static void kserdes_show_lane_config(struct device *dev,
> +				     struct kserdes_lane_config *lc)
> +{
> +	dev_info(dev, "%s\n", lc->enable ? "enable" : "disable");
> +	dev_info(dev, "ctrl_rate 0x%x\n", lc->ctrl_rate);
> +	dev_info(dev, "rx_start %u %u\n",
> +		 lc->rx_start.att, lc->rx_start.boost);
> +	dev_info(dev, "rx_force %u %u\n",
> +		 lc->rx_force.att, lc->rx_force.boost);
> +	dev_info(dev, "tx_coeff %u %u %u %u %u\n",
> +		 lc->tx_coeff.c1, lc->tx_coeff.c2, lc->tx_coeff.cm,
> +		 lc->tx_coeff.att, lc->tx_coeff.vreg);
> +	dev_info(dev, "loopback %u\n", lc->loopback);

same here.
> +}
> +
> +static void kserdes_show_config(struct kserdes_config *sc)
> +{
> +	u32 i;
> +
> +	if (!sc->debug)
> +		return;
> +
> +	dev_info(sc->dev, "serdes regs 0x%p\n", sc->regs);
> +	if (sc->peripheral_regmap)
> +		dev_info(sc->dev, "peripheral regmap handle defined\n");
> +	dev_info(sc->dev, "phy_type %u\n", sc->phy_type);
> +	dev_info(sc->dev, "clk_rate %u\n", sc->clk_rate);
> +	dev_info(sc->dev, "link_rate %u\n", sc->link_rate);
> +	dev_info(sc->dev, "lanes %u\n", sc->lanes);
> +	if ((sc->phy_type == KSERDES_PHY_XGE) && sc->pcsr_regmap)
> +		dev_info(sc->dev, "pcsr regmap handle defined\n");
> +
> +	if (sc->firmware) {
> +		kserdes_show_fw_config(sc);
> +		return;
> +	} else if (sc->init_fw) {
> +		dev_info(sc->dev, "init fw: %s\n", sc->init_fw);
> +	}
> +
> +	dev_info(sc->dev, "rx-force-%s\n",
> +		 (sc->rx_force_enable ? "enable" : "disable"));
> +
> +	for (i = 0; i < sc->lanes; i++) {
> +		dev_info(sc->dev, "lane[%u]:\n", i);
> +		kserdes_show_lane_config(sc->dev, &sc->lane[i]);
> +	}
here too.

> +}
> +
> +static int kserdes_lanes_enable(struct kserdes_config *sc)
> +{
> +	int ret = -EINVAL;
> +
> +	if (sc->phy_type == KSERDES_PHY_SGMII)
> +		ret = kserdes_sgmii_lanes_enable(sc);
> +	else if (sc->phy_type == KSERDES_PHY_XGE)
> +		ret = kserdes_xge_lanes_enable(sc);
> +	else if (sc->phy_type == KSERDES_PHY_PCIE)
> +		ret = kserdes_pcie_lanes_enable(sc);

switch case here?
> +
> +	return ret;
> +}
> +
> +static int kserdes_init(struct phy *phy)
> +{
> +	struct kserdes_dev *sd = phy_get_drvdata(phy);
> +	struct kserdes_config *sc = &sd->sc;
> +	int ret;
> +
> +	if (sc->phy_type == KSERDES_PHY_SGMII)
> +		ret = kserdes_sgmii_init(sc);
> +	else if (sc->phy_type == KSERDES_PHY_XGE)
> +		ret = kserdes_xge_init(sc);
> +	else if (sc->phy_type == KSERDES_PHY_PCIE)
> +		ret = kserdes_pcie_init(sc);
> +	else
> +		ret = -EINVAL;

use switch case instead.
> +
> +	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_info(sd->dev, "serdes config done lanes(mask) 0x%x\n", ret);

dev_dbg?
> +
> +done:
> +	return ret;
> +}
> +
> +struct phy *kserdes_phy_xlate(struct device *dev, struct of_phandle_args *args)
> +{
> +	struct kserdes_dev *sd = dev_get_drvdata(dev);

Why not use the default xlate provided by phy-core? xlates should only
be defined if the driver has to use arguments provided in the PHY specifier.
> +
> +	return sd->phy;
> +}
> +
> +static int kserdes_get_lane_bindings(struct device *dev,
> +				     struct device_node *np,
> +				     struct kserdes_lane_config *lc)
> +{
> +	struct kserdes_equalizer *eq;
> +	struct kserdes_tx_coeff *tc;
> +
> +	if (of_find_property(np, "disable", NULL))
> +		lc->enable = 0;
> +	else
> +		lc->enable = 1;
> +
> +	dev_dbg(dev, "lane enable: %d\n", lc->enable);
> +
> +	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 = 1;
> +	else
> +		lc->loopback = 0;
> +
> +	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->clk_rate		= KSERDES_CLOCK_RATE_156P25M;
> +	sc->link_rate		= KSERDES_LINK_RATE_1P25G;
> +	sc->lanes		= 4;
> +	sc->rx_force_enable	= 0;
> +
> +	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->clk_rate		= KSERDES_CLOCK_RATE_156P25M;
> +	sc->link_rate		= KSERDES_LINK_RATE_10P3125G;
> +	sc->lanes		= 2;
> +	sc->rx_force_enable	= 0;
> +
> +	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->clk_rate		= KSERDES_CLOCK_RATE_100M;
> +	sc->link_rate		= KSERDES_LINK_RATE_5G;
> +	sc->lanes		= 2;
> +	sc->rx_force_enable	= 0;
> +
> +	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_get_properties(struct kserdes_dev *sd,
> +				  struct device_node *np)

kserdes_of_parse?
> +{
> +	struct kserdes_config *sc = &sd->sc;
> +	struct device_node *lp;
> +	struct device *dev = sd->dev;
> +	struct resource res;
> +	void __iomem *regs;
> +	const char *phy_type;
> +	char name[16] = {'l', 'a', 'n', 'e'};
> +	int ret, i;
> +
> +	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;
> +
> +	ret = of_property_read_string(np, "phy-type", &phy_type);

use compatible property for this.
> +	if (!ret) {
> +		if (strcmp(phy_type, "sgmii") == 0)
> +			sc->phy_type = KSERDES_PHY_SGMII;
> +		else if (strcmp(phy_type, "xge") == 0)
> +			sc->phy_type = KSERDES_PHY_XGE;
> +		else if (strcmp(phy_type, "pcie") == 0)
> +			sc->phy_type = KSERDES_PHY_PCIE;
> +		else
> +			return -EINVAL;
> +	}
> +
> +	sc->dev = dev;
> +
> +	/* Set the defaults base on phy type */
> +	kserdes_set_defaults(sc, sc->phy_type);
> +
> +	if (of_property_read_bool(np, "syscon-peripheral")) {
> +		sc->peripheral_regmap =
> +			syscon_regmap_lookup_by_phandle(np,
> +							"syscon-peripheral");
> +		if (IS_ERR(sc->peripheral_regmap)) {
> +			dev_err(sc->dev,
> +				"failed to get syscon-peripheral regmap\n");
> +			return PTR_ERR(sc->peripheral_regmap);
> +		}
> +	}
> +
> +	if (of_property_read_bool(np, "syscon-link")) {
> +		sc->pcsr_regmap =
> +			syscon_regmap_lookup_by_phandle(np, "syscon-link");
> +		if (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, "refclk-khz", &sc->clk_rate))
> +		dev_info(dev, "use default refclk-khz: %u\n", sc->clk_rate);
> +
> +	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, "max-lanes", &sc->lanes))
> +		dev_info(dev, "use default max-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);
> +	}
> +
> +	sc->debug = of_property_read_bool(np, "debug");
> +
> +	if (of_find_property(np, "rx-force-enable", NULL))
> +		sc->rx_force_enable = 1;
> +	else
> +		sc->rx_force_enable = 0;
> +
> +	for (i = 0; i < sc->lanes; i++) {
> +		sprintf(&name[4], "%d", i);
> +		lp = of_find_node_by_name(np, name);
> +		if (lp) {
> +			if (kserdes_get_lane_bindings(dev, lp, &sc->lane[i]))
> +				return -EINVAL;
> +		}
> +	}
> +
> +	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_get_properties(sd, np);
> +	if (ret)
> +		return ret;
> +
> +	kserdes_show_config(&sd->sc);
> +
> +	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,
> +						     kserdes_phy_xlate);
> +
> +	if (IS_ERR(phy_provider))
> +		return PTR_ERR_OR_ZERO(phy_provider);
> +
> +	dev_info(&pdev->dev, "probed");

This is not needed. Maybe dev_vdbg?
> +	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",
> +		.owner = THIS_MODULE,

.owner is not required.
> +	}
> +};
> +
> +static int __init keystone_serdes_phy_init(void)
> +{
> +	return platform_driver_register(&kserdes_driver);
> +}
> +subsys_initcall(keystone_serdes_phy_init);

this should be module_init.

-Kishon

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

* RE: [PATCH 1/3] phy: keystone: serdes driver for gbe 10gbe and pcie
  2015-10-13 22:58   ` Kishon Vijay Abraham I
@ 2015-10-14 15:15     ` Kwok, WingMan
  0 siblings, 0 replies; 10+ messages in thread
From: Kwok, WingMan @ 2015-10-14 15:15 UTC (permalink / raw)
  To: KISHON VIJAY ABRAHAM, 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, linux@arm.linux.org.uk,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org

SGVsbG8sDQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogS0lTSE9OIFZJ
SkFZIEFCUkFIQU0NCj4gU2VudDogVHVlc2RheSwgT2N0b2JlciAxMywgMjAxNSA2OjU4IFBNDQo+
IFRvOiBLd29rLCBXaW5nTWFuOyByb2JoK2R0QGtlcm5lbC5vcmc7IHBhd2VsLm1vbGxAYXJtLmNv
bTsNCj4gbWFyay5ydXRsYW5kQGFybS5jb207IGlqYytkZXZpY2V0cmVlQGhlbGxpb24ub3JnLnVr
OyBnYWxha0Bjb2RlYXVyb3JhLm9yZzsNCj4gUXVhZHJvcywgUm9nZXI7IEthcmljaGVyaSwgTXVy
YWxpZGhhcmFuOyBiaGVsZ2Fhc0Bnb29nbGUuY29tOw0KPiBzc2FudG9zaEBrZXJuZWwub3JnOyBs
aW51eEBhcm0ubGludXgub3JnLnVrOyBkZXZpY2V0cmVlQHZnZXIua2VybmVsLm9yZzsNCj4gbGlu
dXgta2VybmVsQHZnZXIua2VybmVsLm9yZzsgbGludXgtcGNpQHZnZXIua2VybmVsLm9yZzsgbGlu
dXgtYXJtLQ0KPiBrZXJuZWxAbGlzdHMuaW5mcmFkZWFkLm9yZw0KPiBTdWJqZWN0OiBSZTogW1BB
VENIIDEvM10gcGh5OiBrZXlzdG9uZTogc2VyZGVzIGRyaXZlciBmb3IgZ2JlIDEwZ2JlIGFuZA0K
PiBwY2llDQo+IA0KPiBIaSwNCj4gDQo+IE9uIFR1ZXNkYXkgMTMgT2N0b2JlciAyMDE1IDExOjM0
IFBNLCBXaW5nTWFuIEt3b2sgd3JvdGU6DQo+ID4gT24gVEkncyBLZXlzdG9uZSBwbGF0Zm9ybXMs
IHNldmVyYWwgcGVyaXBoZXJhbHMgc3VjaCBhcyB0aGUNCj4gPiBnYmUgZXRoZXJuZXQgc3dpdGNo
LCAxMGdiZSBldGhlcm5ldCBzd2l0Y2ggYW5kIFBDSWUgY29udHJvbGxlcg0KPiA+IHJlcXVpcmUg
dGhlIHVzZSBvZiBhIFNlckRlcyBmb3IgY29udmVydGluZyBTb0MgcGFyYWxsZWwgZGF0YSBpbnRv
DQo+ID4gc2VyaWFsaXplZCBkYXRhIHRoYXQgY2FuIGJlIG91dHB1dCBvdmVyIGEgaGlnaC1zcGVl
ZCBlbGVjdHJpY2FsDQo+ID4gaW50ZXJmYWNlLCBhbmQgYWxzbyBjb252ZXJ0aW5nIGhpZ2gtc3Bl
ZWQgc2VyaWFsIGlucHV0IGRhdGENCj4gPiBpbnRvIHBhcmFsbGVsIGRhdGEgdGhhdCBjYW4gYmUg
cHJvY2Vzc2VkIGJ5IHRoZSBTb0MuICBUaGUNCj4gPiBTZXJEZXNlcyB1c2VkIGJ5IHRob3NlIHBl
cmlwaGVyYWxzLCB0aG91Z2ggdGhleSBtYXkgYmUgZGlmZmVyZW50LA0KPiA+IGFyZSBsYXJnZWx5
IHNpbWlsYXIgaW4gZnVuY3Rpb25hbGl0eSBhbmQgc2V0dXAuDQo+ID4NCj4gPiBUaGlzIHBhdGNo
IHByb3ZpZGVzIGEgU2VyRGVzIHBoeSBkcml2ZXIgaW1wbGVtZW50YXRpb24gdGhhdCBjYW4gYmUN
Cj4gPiB1c2VkIGJ5IHRoZSBhYm92ZSBtZW50aW9uZWQgcGVyaXBoZXJhbCBkcml2ZXJzIHRvIGNv
bmZpZ3VyZSB0aGVpcg0KPiA+IHJlc3BlY3RpdmUgU2VyRGVzZXMuDQo+ID4NCj4gPiBTaWduZWQt
b2ZmLWJ5OiBXaW5nTWFuIEt3b2sgPHcta3dvazJAdGkuY29tPg0KPiA+IC0tLQ0KPiA+ICBEb2N1
bWVudGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3MvcGh5L3RpLXBoeS50eHQgfCAgMjU2ICsrKw0K
PiA+ICBkcml2ZXJzL3BoeS9LY29uZmlnICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAg
ICA4ICsNCj4gPiAgZHJpdmVycy9waHkvTWFrZWZpbGUgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIHwgICAgMSArDQo+ID4gIGRyaXZlcnMvcGh5L3BoeS1rZXlzdG9uZS1zZXJkZXMuYyAgICAg
ICAgICAgICAgICB8IDI0NjUNCj4gKysrKysrKysrKysrKysrKysrKysrKw0KPiA+ICA0IGZpbGVz
IGNoYW5nZWQsIDI3MzAgaW5zZXJ0aW9ucygrKQ0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJp
dmVycy9waHkvcGh5LWtleXN0b25lLXNlcmRlcy5jDQo+ID4NCj4gDQo+IDxzbmlwPg0KPiANCj4g
PiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9waHkvS2NvbmZpZyBiL2RyaXZlcnMvcGh5L0tjb25maWcN
Cj4gPiBpbmRleCA0N2RhNTczLi44ZmMyMWE0IDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMvcGh5
L0tjb25maWcNCj4gPiArKysgYi9kcml2ZXJzL3BoeS9LY29uZmlnDQo+ID4gQEAgLTExOCw2ICsx
MTgsMTQgQEAgY29uZmlnIFBIWV9SQ0FSX0dFTjINCj4gPiAgCWhlbHANCj4gPiAgCSAgU3VwcG9y
dCBmb3IgVVNCIFBIWSBmb3VuZCBvbiBSZW5lc2FzIFItQ2FyIGdlbmVyYXRpb24gMiBTb0NzLg0K
PiA+DQo+ID4gK2NvbmZpZyBQSFlfVElfS0VZU1RPTkVfU0VSREVTDQo+ID4gKwl0cmlzdGF0ZSAi
VEkgS2V5c3RvbmUgU2VyRGVzIFBIWSBzdXBwb3J0Ig0KPiA+ICsJZGVwZW5kcyBvbiBPRiAmJiBB
UkNIX0tFWVNUT05FDQo+ID4gKwlzZWxlY3QgR0VORVJJQ19QSFkNCj4gPiArCWhlbHANCj4gPiAr
CSAgVGhpcyBvcHRpb24gZW5hYmxlcyBzdXBwb3J0IGZvciBUSSBLZXlzdG9uZSBTZXJEZXMgUEhZ
IGZvdW5kDQo+ID4gKwkgIGluIHBlcmlwaGVyYWxzIEdCRSwgMTBHQkUgYW5kIFBDSWUuDQo+ID4g
Kw0KPiA+ICBjb25maWcgT01BUF9DT05UUk9MX1BIWQ0KPiA+ICAJdHJpc3RhdGUgIk9NQVAgQ09O
VFJPTCBQSFkgRHJpdmVyIg0KPiA+ICAJZGVwZW5kcyBvbiBBUkNIX09NQVAyUExVUyB8fCBDT01Q
SUxFX1RFU1QNCj4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9waHkvTWFrZWZpbGUgYi9kcml2ZXJz
L3BoeS9NYWtlZmlsZQ0KPiA+IGluZGV4IGE1YjE4YzEuLjhjYjM2NWIgMTAwNjQ0DQo+ID4gLS0t
IGEvZHJpdmVycy9waHkvTWFrZWZpbGUNCj4gPiArKysgYi9kcml2ZXJzL3BoeS9NYWtlZmlsZQ0K
PiA+IEBAIC00NiwzICs0Niw0IEBAIG9iai0kKENPTkZJR19QSFlfUUNPTV9VRlMpIAkrPSBwaHkt
cWNvbS11ZnMtcW1wLQ0KPiAxNG5tLm8NCj4gPiAgb2JqLSQoQ09ORklHX1BIWV9UVVNCMTIxMCkJ
CSs9IHBoeS10dXNiMTIxMC5vDQo+ID4gIG9iai0kKENPTkZJR19QSFlfQlJDTVNUQl9TQVRBKQkJ
Kz0gcGh5LWJyY21zdGItc2F0YS5vDQo+ID4gIG9iai0kKENPTkZJR19QSFlfUElTVEFDSElPX1VT
QikJCSs9IHBoeS1waXN0YWNoaW8tdXNiLm8NCj4gPiArb2JqLSQoQ09ORklHX1BIWV9USV9LRVlT
VE9ORV9TRVJERVMpCSs9IHBoeS1rZXlzdG9uZS1zZXJkZXMubw0KPiA+IGRpZmYgLS1naXQgYS9k
cml2ZXJzL3BoeS9waHkta2V5c3RvbmUtc2VyZGVzLmMgYi9kcml2ZXJzL3BoeS9waHktDQo+IGtl
eXN0b25lLXNlcmRlcy5jDQo+ID4gbmV3IGZpbGUgbW9kZSAxMDA2NDQNCj4gPiBpbmRleCAwMDAw
MDAwLi5jNzNkNGRlDQo+ID4gLS0tIC9kZXYvbnVsbA0KPiA+ICsrKyBiL2RyaXZlcnMvcGh5L3Bo
eS1rZXlzdG9uZS1zZXJkZXMuYw0KPiA+IEBAIC0wLDAgKzEsMjQ2NSBAQA0KPiA+ICsvKg0KPiA+
ICsgKiBUZXhhcyBJbnN0cnVtZW50cyBLZXlzdG9uZSBTZXJEZXMgZHJpdmVyDQo+ID4gKyAqIEF1
dGhvcnM6IFdpbmdNYW4gS3dvayA8dy1rd29rMkB0aS5jb20+DQo+ID4gKyAqDQo+ID4gKyAqIFRo
aXMgaXMgdGhlIFNlckRlcyBQaHkgZHJpdmVyIGZvciBLZXlzdG9uZSBkZXZpY2VzLiBUaGlzIGlz
DQo+ID4gKyAqIHJlcXVpcmVkIHRvIHN1cHBvcnQgUENJZSBSQyBmdW5jdGlvbmFsaXR5IGJhc2Vk
IG9uIGRlc2lnbndhcmUNCj4gPiArICogUENJZSBoYXJkd2FyZSwgZ2JlIGFuZCAxMGdiZSBmb3Vu
ZCBvbiB0aGVzZSBkZXZpY2VzLg0KPiA+ICsgKg0KPiA+ICsgKiBDb3B5cmlnaHQgKEMpIDIwMTUg
VGV4YXMgSW5zdHJ1bWVudHMgSW5jb3Jwb3JhdGVkIC0NCj4gaHR0cDovL3d3dy50aS5jb20vDQo+
ID4gKyAqDQo+ID4gKyAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJl
ZGlzdHJpYnV0ZSBpdCBhbmQvb3INCj4gPiArICogbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBv
ZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMNCj4gPiArICogcHVibGlzaGVkIGJ5
IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24gdmVyc2lvbiAyLg0KPiA+ICsgKg0KPiA+ICsg
KiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgImFzIGlzIiBXSVRIT1VUIEFOWSBXQVJSQU5U
WSBvZiBhbnkNCj4gPiArICoga2luZCwgd2hldGhlciBleHByZXNzIG9yIGltcGxpZWQ7IHdpdGhv
dXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eQ0KPiA+ICsgKiBvZiBNRVJDSEFOVEFCSUxJVFkg
b3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlDQo+ID4gKyAqIEdO
VSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuDQo+ID4gKyAqDQo+ID4g
KyAqIENvcHlyaWdodCAoQykgMjAxNSBUZXhhcyBJbnN0cnVtZW50cyBJbmNvcnBvcmF0ZWQgLQ0K
PiBodHRwOi8vd3d3LnRpLmNvbS8NCj4gPiArICoNCj4gPiArICogUmVkaXN0cmlidXRpb24gYW5k
IHVzZSBpbiBzb3VyY2UgYW5kIGJpbmFyeSBmb3Jtcywgd2l0aCBvciB3aXRob3V0DQo+ID4gKyAq
IG1vZGlmaWNhdGlvbiwgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZSBmb2xsb3dpbmcg
Y29uZGl0aW9ucw0KPiA+ICsgKiBhcmUgbWV0Og0KPiA+ICsgKg0KPiA+ICsgKiBSZWRpc3RyaWJ1
dGlvbnMgb2Ygc291cmNlIGNvZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodA0KPiA+
ICsgKiBub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRp
c2NsYWltZXIuDQo+ID4gKyAqDQo+ID4gKyAqIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9y
bSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0DQo+ID4gKyAqIG5vdGljZSwgdGhp
cyBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lciBpbiB0aGUN
Cj4gPiArICogZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHByb3ZpZGVkIHdp
dGggdGhlDQo+ID4gKyAqIGRpc3RyaWJ1dGlvbi4NCj4gPiArICoNCj4gPiArICogTmVpdGhlciB0
aGUgbmFtZSBvZiBUZXhhcyBJbnN0cnVtZW50cyBJbmNvcnBvcmF0ZWQgbm9yIHRoZSBuYW1lcyBv
Zg0KPiA+ICsgKiBpdHMgY29udHJpYnV0b3JzIG1heSBiZSB1c2VkIHRvIGVuZG9yc2Ugb3IgcHJv
bW90ZSBwcm9kdWN0cyBkZXJpdmVkDQo+ID4gKyAqIGZyb20gdGhpcyBzb2Z0d2FyZSB3aXRob3V0
IHNwZWNpZmljIHByaW9yIHdyaXR0ZW4gcGVybWlzc2lvbi4NCj4gPiArICoNCj4gPiArICogVEhJ
UyBTT0ZUV0FSRSBJUyBQUk9WSURFRCBCWSBUSEUgQ09QWVJJR0hUIEhPTERFUlMgQU5EIENPTlRS
SUJVVE9SUw0KPiA+ICsgKiAiQVMgSVMiIEFORCBBTlkgRVhQUkVTUyBPUiBJTVBMSUVEIFdBUlJB
TlRJRVMsIElOQ0xVRElORywgQlVUIE5PVA0KPiA+ICsgKiBMSU1JVEVEIFRPLCBUSEUgSU1QTElF
RCBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSBBTkQgRklUTkVTUyBGT1INCj4gPiArICog
QSBQQVJUSUNVTEFSIFBVUlBPU0UgQVJFIERJU0NMQUlNRUQuIElOIE5PIEVWRU5UIFNIQUxMIFRI
RSBDT1BZUklHSFQNCj4gPiArICogT1dORVIgT1IgQ09OVFJJQlVUT1JTIEJFIExJQUJMRSBGT1Ig
QU5ZIERJUkVDVCwgSU5ESVJFQ1QsIElOQ0lERU5UQUwsDQo+ID4gKyAqIFNQRUNJQUwsIEVYRU1Q
TEFSWSwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTIChJTkNMVURJTkcsIEJVVCBOT1QNCj4gPiAr
ICogTElNSVRFRCBUTywgUFJPQ1VSRU1FTlQgT0YgU1VCU1RJVFVURSBHT09EUyBPUiBTRVJWSUNF
UzsgTE9TUyBPRiBVU0UsDQo+ID4gKyAqIERBVEEsIE9SIFBST0ZJVFM7IE9SIEJVU0lORVNTIElO
VEVSUlVQVElPTikgSE9XRVZFUiBDQVVTRUQgQU5EIE9OIEFOWQ0KPiA+ICsgKiBUSEVPUlkgT0Yg
TElBQklMSVRZLCBXSEVUSEVSIElOIENPTlRSQUNULCBTVFJJQ1QgTElBQklMSVRZLCBPUiBUT1JU
DQo+ID4gKyAqIChJTkNMVURJTkcgTkVHTElHRU5DRSBPUiBPVEhFUldJU0UpIEFSSVNJTkcgSU4g
QU5ZIFdBWSBPVVQgT0YgVEhFIFVTRQ0KPiA+ICsgKiBPRiBUSElTIFNPRlRXQVJFLCBFVkVOIElG
IEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFLg0KPiA+ICsgKg0KPiA+
ICsgKiBUaGUgY29udGVudHMgb2YgdGhlIGFycmF5IGsyXzEwMG1oel9wY2llXzVnYnBzX3NlcmRl
cyBpcyBjb3ZlcmVkIGJ5DQo+IEJTRA0KPiA+ICsgKiBsaWNlbnNlLg0KPiA+ICsgKi8NCj4gPiAr
I2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvaW8uaD4NCj4g
PiArI2luY2x1ZGUgPGxpbnV4L21mZC9zeXNjb24uaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L2Rl
dmljZS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvZXJyLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51
eC9kZWxheS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvcmFuZG9tLmg+DQo+ID4gKyNpbmNsdWRl
IDxsaW51eC9maXJtd2FyZS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvb2YuaD4NCj4gPiArI2lu
Y2x1ZGUgPGxpbnV4L29mX2FkZHJlc3MuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L29mX3BsYXRm
b3JtLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9yZWdtYXAuaD4NCj4gPiArI2luY2x1ZGUgPGxp
bnV4L3BoeS9waHkuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L3BsYXRmb3JtX2RldmljZS5oPg0K
PiA+ICsNCj4gPiArLyoNCj4gPiArICogS2V5c3RvbmUyIFNFUkRFUyByZWdpc3RlcnMNCj4gPiAr
ICovDQo+ID4gKy8qIDB4MWZjMCAtIDB4MWZmZiAqLw0KPiA+ICsjZGVmaW5lIEtTRVJERVNfU1Nf
T0ZGU0VUCTB4MWZjMA0KPiA+ICsvKiAweDFmYzAgKi8NCj4gPiArI2RlZmluZSBNT0RfVkVSX1JF
RwkJKEtTRVJERVNfU1NfT0ZGU0VUICsgMHgwMCkNCj4gPiArLyogMHgxZmM0ICovDQo+ID4gKyNk
ZWZpbmUgTUVNX0FEUl9SRUcJCShLU0VSREVTX1NTX09GRlNFVCArIDB4MDQpDQo+ID4gKy8qIDB4
MWZjOCAqLw0KPiA+ICsjZGVmaW5lIE1FTV9EQVRfUkVHCQkoS1NFUkRFU19TU19PRkZTRVQgKyAw
eDA4KQ0KPiA+ICsvKiAweDFmY2MgKi8NCj4gPiArI2RlZmluZSBNRU1fREFUSU5DX1JFRwkJKEtT
RVJERVNfU1NfT0ZGU0VUICsgMHgwYykNCj4gPiArLyogMHgxZmQwICovDQo+ID4gKyNkZWZpbmUg
Q1BVX0NUUkxfUkVHCQkoS1NFUkRFU19TU19PRkZTRVQgKyAweDEwKQ0KPiA+ICsvKiAweDFmZTAs
IDB4MWZlNCAqLw0KPiA+ICsjZGVmaW5lIExBTkVfQ1RSTF9TVFNfUkVHKHgpCShLU0VSREVTX1NT
X09GRlNFVCArIDB4MjAgKyAoeCAqIDB4MDQpKQ0KPiA+ICsvKiAweDFmZjAgKi8NCj4gPiArI2Rl
ZmluZSBMSU5LX0xPU1NfV0FJVF9SRUcJKEtTRVJERVNfU1NfT0ZGU0VUICsgMHgzMCkNCj4gPiAr
LyogMHgxZmY0ICovDQo+ID4gKyNkZWZpbmUgUExMX0NUUkxfUkVHCQkoS1NFUkRFU19TU19PRkZT
RVQgKyAweDM0KQ0KPiA+ICsNCj4gPiArLyogQ01VMCBTUyAweDAwMDAgLSAweDAxZmYgKi8NCj4g
PiArI2RlZmluZSBDTVUwX1NTX09GRlNFVAkJMHgwMDAwDQo+ID4gKyNkZWZpbmUgQ01VMF9SRUco
eCkJCShDTVUwX1NTX09GRlNFVCArIHgpDQo+ID4gKw0KPiA+ICsvKiBMQU5FIFNTIDB4MDIwMCAt
IDB4MDNmZiwgMHgwNDAwIC0gMHgwNWZmLCAuLi4gKi8NCj4gPiArI2RlZmluZSBMQU5FMF9TU19P
RkZTRVQJCTB4MDIwMA0KPiA+ICsjZGVmaW5lIExBTkVYX1NTX09GRlNFVCh4KQkoTEFORTBfU1Nf
T0ZGU0VUICogKHggKyAxKSkNCj4gPiArI2RlZmluZSBMQU5FWF9SRUcoeCwgeSkJCShMQU5FWF9T
U19PRkZTRVQoeCkgKyB5KQ0KPiA+ICsNCj4gPiArLyogQ01MIFNTIDB4MGEwMCAtIDB4MGJmZiAq
Lw0KPiA+ICsjZGVmaW5lIENNTF9TU19PRkZTRVQJCTB4MGEwMA0KPiA+ICsjZGVmaW5lIENNTF9S
RUcoeCkJCShDTUxfU1NfT0ZGU0VUICsgeCkNCj4gPiArDQo+ID4gKy8qIENNVTEgU1MgMHgwYzAw
IC0gMHgwZGZmICovDQo+ID4gKyNkZWZpbmUgQ01VMV9TU19PRkZTRVQJCTB4MGMwMA0KPiA+ICsj
ZGVmaW5lIENNVTFfUkVHKHgpCQkoQ01VMV9TU19PRkZTRVQgKyB4KQ0KPiA+ICsNCj4gPiArLyoN
Cj4gPiArICogWEdFIFBDUy1SIHJlZ2lzdGVycw0KPiA+ICsgKi8NCj4gPiArI2RlZmluZSBQQ1NS
X09GRlNFVCh4KQkJKHggKiAweDgwKQ0KPiA+ICsNCj4gPiArI2RlZmluZSBQQ1NSX1RYX0NUTCh4
KQkJKFBDU1JfT0ZGU0VUKHgpICsgMHgwMCkNCj4gPiArI2RlZmluZSBQQ1NSX1RYX1NUQVRVUyh4
KQkoUENTUl9PRkZTRVQoeCkgKyAweDA0KQ0KPiA+ICsjZGVmaW5lIFBDU1JfUlhfQ1RMKHgpCQko
UENTUl9PRkZTRVQoeCkgKyAweDA4KQ0KPiA+ICsjZGVmaW5lIFBDU1JfUlhfU1RBVFVTKHgpCShQ
Q1NSX09GRlNFVCh4KSArIDB4MEMpDQo+ID4gKw0KPiA+ICsjZGVmaW5lIFhHRV9DVFJMX09GRlNF
VAkJMHgwYw0KPiA+ICsjZGVmaW5lIFBDSUVfUExfR0VOMl9PRkZTRVQJMHgxODBjDQo+ID4gKw0K
PiA+ICsjZGVmaW5lIHJlZ19ybXcoYWRkciwgdmFsdWUsIG1hc2spIFwNCj4gPiArCV9fcmF3X3dy
aXRlbCgoKF9fcmF3X3JlYWRsKGFkZHIpICYgKH4obWFzaykpKSB8IFwNCj4gPiArCQkJKHZhbHVl
ICYgKG1hc2spKSksIChhZGRyKSkNCj4gPiArDQo+ID4gKy8qIGJpdCBtYXNrIGZyb20gYml0LWEg
dG8gYml0LWIgaW5jbHVzaXZlICovDQo+ID4gKyNkZWZpbmUgTUFTSyhtc2IsIGxzYikgXA0KPiA+
ICsJKCgoKG1zYikgLSAobHNiKSkgPT0gMzEpID8gMHhmZmZmZmZmZiA6ICBcDQo+ID4gKwkJKCgo
KHUzMikxIDw8ICgobXNiKSAtIChsc2IpICsgMSkpIC0gMSkgPDwgKGxzYikpKQ0KPiANCj4gdXNl
IEdFTk1BU0sgaW5zdGVhZD8NCg0Kd2lsbCBjaGFuZ2UgdG8gR0VOTUFTSy4NCg0KPiA+ICsNCj4g
PiArLyogUmVwbGFjZXMgYml0IGZpZWxkIFttc2I6bHNiXSBpbiByZWdpc3RlciBsb2NhdGVkDQo+
ID4gKyAqIGF0IChiYXNlICsgb2Zmc2V0KSBieSB2YWwNCj4gPiArICovDQo+ID4gKyNkZWZpbmUg
RklOU1IoYmFzZSwgb2Zmc2V0LCBtc2IsIGxzYiwgdmFsKSBcDQo+ID4gKwlyZWdfcm13KChiYXNl
KSArIChvZmZzZXQpLCAoKHZhbCkgPDwgKGxzYikpLCBNQVNLKChtc2IpLCAobHNiKSkpDQo+ID4g
Kw0KPiA+ICsvKiBUaGlzIHZlcnNpb24gb2YgRkVYVFIgaXMgTk9UIHNhZmUgZm9yIG1zYiA9IDMx
LCBsc2IgPSAwDQo+ID4gKyAqIGJ1dCB0aGVuIHdoeSB3b3VsZCB3ZSBuZWVkIEZFWFRSIGZvciB0
aGF0IGNhc2UuDQo+ID4gKyAqLw0KPiA+ICsjZGVmaW5lIEZFWFRSKHZhbCwgbXNiLCBsc2IpIFwN
Cj4gPiArCSgoKHZhbCkgPj4gKGxzYikpICYgKCgxIDw8ICgobXNiKSAtIChsc2IpICsgMSkpIC0g
MSkpDQo+ID4gKw0KPiA+ICsjZGVmaW5lIE1PRF9WRVIoc2VyZGVzKSBcDQo+ID4gKwkoKGtzZXJk
ZXNfcmVhZGwoc2VyZGVzLCBNT0RfVkVSX1JFRykgPj4gMTYpICYgMHhmZmZmKQ0KPiA+ICsNCj4g
PiArI2RlZmluZSBQSFlfQShzZXJkZXMpIChNT0RfVkVSKHNlcmRlcykgIT0gMHg0ZWJhKQ0KPiA+
ICsNCj4gPiArI2RlZmluZSBGT1VSX0xBTkUoc2VyZGVzKSBcDQo+ID4gKwkoKE1PRF9WRVIoc2Vy
ZGVzKSA9PSAweDRlYjkpIHx8IChNT0RfVkVSKHNlcmRlcykgPT0gMHg0ZWJkKSkNCj4gPiArDQo+
ID4gKyNkZWZpbmUgTEFORV9FTkFCTEUoc2MsIG4pICgoc2MpLT5sYW5lW25dLmVuYWJsZSkNCj4g
PiArDQo+ID4gKyNkZWZpbmUgZm9yX2VhY2hfZW5hYmxlX2xhbmUoZnVuYywgc2MpCQkJXA0KPiA+
ICsJZG8gewkJCQkJCVwNCj4gPiArCQlpbnQgaTsJCQkJCVwNCj4gPiArCQlmb3IgKGkgPSAwOyBp
IDwgKHNjKS0+bGFuZXM7IGkrKykgewlcDQo+ID4gKwkJCWlmICghTEFORV9FTkFCTEUoKHNjKSwg
aSkpCVwNCj4gPiArCQkJCWNvbnRpbnVlOwkJXA0KPiA+ICsJCQkJCQkJXA0KPiA+ICsJCQkoZnVu
YykoKHNjKSwgaSk7CQlcDQo+ID4gKwkJfQkJCQkJXA0KPiA+ICsJfSB3aGlsZSAoMCkNCj4gPiAr
DQo+ID4gKyNkZWZpbmUgZm9yX2VhY2hfbGFuZShmdW5jLCBzYykJCQkJXA0KPiA+ICsJZG8gewkJ
CQkJCVwNCj4gPiArCQlpbnQgaTsJCQkJCVwNCj4gPiArCQlmb3IgKGkgPSAwOyBpIDwgKHNjKS0+
bGFuZXM7IGkrKykgewlcDQo+ID4gKwkJCShmdW5jKSgoc2MpLCBpKTsJCVwNCj4gPiArCQl9CQkJ
CQlcDQo+ID4gKwl9IHdoaWxlICgwKQ0KPiA+ICsNCj4gPiArI2RlZmluZSBmb3JfZWFjaF9lbmFi
bGVfbGFuZV9yZXR1cm4oZnVuYywgc2MsIHIpCVwNCj4gPiArCWRvIHsJCQkJCQlcDQo+ID4gKwkJ
aW50IGk7CQkJCQlcDQo+ID4gKwkJKHIpID0gMDsJCQkJXA0KPiA+ICsJCWZvciAoaSA9IDA7IGkg
PCAoc2MpLT5sYW5lczsgaSsrKSB7CVwNCj4gPiArCQkJaWYgKCFMQU5FX0VOQUJMRSgoc2MpLCBp
KSkJXA0KPiA+ICsJCQkJY29udGludWU7CQlcDQo+ID4gKwkJCQkJCQlcDQo+ID4gKwkJCShyKSA9
IChmdW5jKSgoc2MpLCBpKTsJCVwNCj4gPiArCQkJaWYgKChyKSkJCQlcDQo+ID4gKwkJCQlicmVh
azsJCQlcDQo+ID4gKwkJfQkJCQkJXA0KPiA+ICsJfSB3aGlsZSAoMCkNCj4gPiArDQo+ID4gKyNk
ZWZpbmUgZm9yX2VhY2hfbGFuZV9yZXR1cm4oZnVuYywgc2MsIHIpCQlcDQo+ID4gKwlkbyB7CQkJ
CQkJXA0KPiA+ICsJCWludCBpOwkJCQkJXA0KPiA+ICsJCShyKSA9IDA7CQkJCVwNCj4gPiArCQlm
b3IgKGkgPSAwOyBpIDwgKHNjKS0+bGFuZXM7IGkrKykgewlcDQo+ID4gKwkJCShyKSA9IChmdW5j
KSgoc2MpLCBpKTsJCVwNCj4gPiArCQkJaWYgKChyKSkJCQlcDQo+ID4gKwkJCQlicmVhazsJCQlc
DQo+ID4gKwkJfQkJCQkJXA0KPiA+ICsJfSB3aGlsZSAoMCkNCj4gDQo+IE92ZXJ1c2Ugb2YgbWFj
cm9zIGhlcmUgYW5kICpmb3JfZWFjaF9sYW5lX3JldHVybiogaXMgbm90IHVzZWQgaW4gdGhpcw0K
PiBmaWxlIGF0IGFsbC4NCg0Kd2lsbCByZW1vdmUNCg0KPiA+ICsNCj4gPiArI2RlZmluZSBNQVhf
Q09NUEFSQVRPUlMJCQk1DQo+ID4gKyNkZWZpbmUgREZFX09GRlNFVF9TQU1QTEVTCQkxMDANCj4g
PiArDQo+ID4gKy8qIENQVSBDVFJMIGJpdHMgKi8NCj4gPiArI2RlZmluZSBDUFVfRU4JCQlCSVQo
MzEpDQo+ID4gKyNkZWZpbmUgQ1BVX0dPCQkJQklUKDMwKQ0KPiA+ICsjZGVmaW5lIFBPUl9FTgkJ
CUJJVCgyOSkNCj4gPiArI2RlZmluZSBDUFVSRUdfRU4JCUJJVCgyOCkNCj4gPiArI2RlZmluZSBB
VVRPTkVHX0NUTAkJQklUKDI3KQ0KPiA+ICsjZGVmaW5lIERBVEFTUExJVAkJQklUKDI2KQ0KPiA+
ICsjZGVmaW5lIExOS1RSTl9TSUdfREVUCQlCSVQoOCkNCj4gPiArDQo+ID4gKyNkZWZpbmUgQU5F
R19MSU5LX0NUTF8xMEdLUl9NQVNLCU1BU0soMjEsIDIwKQ0KPiA+ICsjZGVmaW5lIEFORUdfTElO
S19DVExfMUdLWF9NQVNLCQlNQVNLKDE3LCAxNikNCj4gPiArI2RlZmluZSBBTkVHX0xJTktfQ1RM
XzFHMTBHX01BU0sgXA0KPiA+ICsJKEFORUdfTElOS19DVExfMTBHS1JfTUFTSyB8IEFORUdfTElO
S19DVExfMUdLWF9NQVNLKQ0KPiA+ICsNCj4gDQo+IDxzbmlwPg0KPiANCj4gPiArc3RhdGljIGlu
bGluZSB2b2lkIGtzZXJkZXNfeGZ3X2dldF9sYW5lX3BhcmFtcyhzdHJ1Y3Qga3NlcmRlc19jb25m
aWcNCj4gKnNjLA0KPiA+ICsJCQkJCSAgICAgICBpbnQgbGFuZSkNCj4gPiArew0KPiA+ICsJc3Ry
dWN0IGtzZXJkZXNfZndfY29uZmlnICpmdyA9ICZzYy0+Znc7DQo+ID4gKwl1MzIgdHhfY3RybCwg
dmFsXzAsIHZhbF8xOw0KPiA+ICsJdTMyIHBoeV9hID0gUEhZX0Eoc2MtPnJlZ3MpOw0KPiA+ICsN
Cj4gPiArCXZhbF8wID0ga3NlcmRlc19yZWFkbChzYy0+cmVncywgTEFORVhfUkVHKGxhbmUsIDB4
MDQpKTsNCj4gPiArCXZhbF8xID0ga3NlcmRlc19yZWFkbChzYy0+cmVncywgTEFORVhfUkVHKGxh
bmUsIDB4MDgpKTsNCj4gPiArDQo+ID4gKwl0eF9jdHJsID0gKCgoKHZhbF8wID4+IDE4KSAmIDB4
MSkgICAgPDwgMjQpIHwJLyogVFhfQ1RSTF9PXzI0ICovDQo+ID4gKwkJICAgKCgodmFsXzEgPj4g
MCkgICYgMHhmZmZmKSA8PCAgOCkgfAkvKiBUWF9DVFJMX09fMjNfOCAqLw0KPiA+ICsJCSAgICgo
KHZhbF8wID4+IDI0KSAmIDB4ZmYpICAgPDwgIDApKTsJLyogVFhfQ1RSTF9PXzdfMCAqLw0KPiA+
ICsNCj4gPiArCWlmIChwaHlfYSkgew0KPiA+ICsJCWZ3LT5jbSA9ICh2YWxfMSA+PiAxMikgJiAw
eGY7DQo+ID4gKwkJZnctPmMxID0gKHZhbF8xID4+IDApICYgMHgxZjsNCj4gPiArCQlmdy0+YzIg
PSAodmFsXzEgPj4gOCkgJiAweGY7DQo+ID4gKwl9IGVsc2Ugew0KPiA+ICsJCWZ3LT5jbSA9ICh0
eF9jdHJsID4+IDE2KSAmIDB4ZjsNCj4gPiArCQlmdy0+YzEgPSAodHhfY3RybCA+PiA4KSAmIDB4
MWY7DQo+ID4gKwkJZnctPmMyID0gKHR4X2N0cmwgPj4gMTMpICYgMHg3Ow0KPiA+ICsJCWZ3LT5j
MiA9IGZ3LT5jMiB8ICgoKHR4X2N0cmwgPj4gMjQpICYgMHgxKSA8PCAzKTsNCj4gPiArCX0NCj4g
PiArDQo+ID4gKwl2YWxfMCA9IF9rc2VyZGVzX3JlYWRfc2VsZWN0X3RidXMoc2MtPnJlZ3MsIGxh
bmUgKyAxLA0KPiA+ICsJCQkJCSAgKHBoeV9hID8gMHgxMSA6IDB4MTApKTsNCj4gPiArCWZ3LT5h
dHRuID0gKHZhbF8wID4+IDQpICYgMHhmOw0KPiA+ICsJZnctPmJvb3N0ID0gKHZhbF8wID4+IDgp
ICYgMHhmOw0KPiA+ICsNCj4gPiArCXZhbF8wID0gX2tzZXJkZXNfcmVhZF9zZWxlY3RfdGJ1cyhz
Yy0+cmVncywgbGFuZSArIDEsIDB4NSk7DQo+ID4gKwlmdy0+ZGxwZiA9ICh2YWxfMCA+PiAyKSAm
IDB4M2ZmOw0KPiA+ICsNCj4gPiArCXZhbF8wID0gX2tzZXJkZXNfcmVhZF9zZWxlY3RfdGJ1cyhz
Yy0+cmVncywgbGFuZSArIDEsIDB4Nik7DQo+ID4gKwlmdy0+Y2RyY2FsID0gKHZhbF8wID4+IDMp
ICYgMHhmZjsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGlubGluZSB2b2lkIGtzZXJkZXNf
eGZ3X21lbV9pbml0KHN0cnVjdCBrc2VyZGVzX2NvbmZpZyAqc2MpDQo+ID4gK3sNCj4gPiArCXN0
cnVjdCBrc2VyZGVzX2Z3X2NvbmZpZyAqZncgPSAmc2MtPmZ3Ow0KPiA+ICsJdTMyIGksIGxhbmVf
Y29uZmlnID0gMCwgbGFuZXMgPSBzYy0+bGFuZXM7DQo+ID4gKw0KPiA+ICsJZm9yIChpID0gMDsg
aSA8IGxhbmVzOyBpKyspDQo+ID4gKwkJbGFuZV9jb25maWcgPSAobGFuZV9jb25maWcgPDwgOCkg
fA0KPiA+ICsJCQkoZnctPmxhbmVfY29uZmlnW2ldICYgMHhmZik7DQo+ID4gKw0KPiA+ICsJbGFu
ZV9jb25maWcgPDw9IDg7DQo+ID4gKw0KPiA+ICsJLyogaW5pdGlhbGl6ZSA2NEIgZGF0YSBtZW0g
Ki8NCj4gPiArCWtzZXJkZXNfd3JpdGVsKHNjLT5yZWdzLCBNRU1fQURSX1JFRywgMHgwMDAwZmZj
MCk7DQo+ID4gKw0KPiA+ICsJZm9yIChpID0gMDsgaSA8IDExOyBpKyspDQo+IA0KPiBXaHkgMTE/
IFRoaXMgbmVlZHMgYSBtYWNyby4NCg0KdGhpcyBpcyBhIG1lbSBvZmZzZXQgaW4gYSBtaWNyb2Nv
bnRyb2xsZXIncw0KaW50ZXJuYWwgbWVtIGluc2lkZSB0aGUgc2VyZGVzLiB3aWxsIHVwZGF0ZQ0K
dG8gYSBtYWNybw0KDQo+ID4gKwkJa3NlcmRlc193cml0ZWwoc2MtPnJlZ3MsIE1FTV9EQVRJTkNf
UkVHLCAweDAwMDAwMDAwKTsNCj4gPiArDQo+ID4gKwkvKiBGbHVzaCA2NCBieXRlcyAxMCwxMSwx
MiwxMyAqLw0KPiA+ICsJa3NlcmRlc193cml0ZWwoc2MtPnJlZ3MsIE1FTV9EQVRJTkNfUkVHLCAw
eDAwMDA5QzlDKTsNCj4gPiArDQo+ID4gKwkvKiBmYXN0IHRyYWluICovDQo+ID4gKwlrc2VyZGVz
X3dyaXRlbChzYy0+cmVncywgTUVNX0RBVElOQ19SRUcsIGZ3LT5mYXN0X3RyYWluKTsNCj4gPiAr
DQo+ID4gKwlrc2VyZGVzX3dyaXRlbChzYy0+cmVncywgTUVNX0RBVElOQ19SRUcsIDB4MDAwMDAw
MDApOw0KPiA+ICsJLyogbGFuZSBzZWVkcyAqLw0KPiA+ICsJa3NlcmRlc193cml0ZWwoc2MtPnJl
Z3MsIE1FTV9EQVRJTkNfUkVHLCBmdy0+bGFuZV9zZWVkcyk7DQo+ID4gKwkvKiBsYW5lIGNvbmZp
ZyAqLw0KPiA+ICsJa3NlcmRlc193cml0ZWwoc2MtPnJlZ3MsIE1FTV9EQVRJTkNfUkVHLCBsYW5l
X2NvbmZpZyk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQga3NlcmRlc194Z2VfaW5p
dChzdHJ1Y3Qga3NlcmRlc19jb25maWcgKnNjKQ0KPiA+ICt7DQo+ID4gKwlpZiAoc2MtPmNsa19y
YXRlICE9IEtTRVJERVNfQ0xPQ0tfUkFURV8xNTZQMjVNKQ0KPiA+ICsJCXJldHVybiAtRUlOVkFM
Ow0KPiA+ICsNCj4gPiArCXJldHVybiBrc2VyZGVzX2xvYWRfaW5pdF9mdyhzYywga3MyX3hnYmVf
c2VyZGVzX2Zpcm13YXJlcywNCj4gPiArCQkJCSAgICBBUlJBWV9TSVpFKGtzMl94Z2JlX3NlcmRl
c19maXJtd2FyZXMpKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGludCBrc2VyZGVzX3Bj
aWVfbGFuZXNfZW5hYmxlKHN0cnVjdCBrc2VyZGVzX2NvbmZpZyAqc2MpDQo+ID4gK3sNCj4gPiAr
CWludCByZXQsIGk7DQo+ID4gKwl1MzIgbGFuZXNfZW5hYmxlID0gMDsNCj4gPiArDQo+ID4gKwlm
b3IgKGkgPSAwOyBpIDwgc2MtPmxhbmVzOyBpKyspIHsNCj4gPiArCQlpZiAoIUxBTkVfRU5BQkxF
KHNjLCBpKSkNCj4gPiArCQkJY29udGludWU7DQo+ID4gKw0KPiA+ICsJCWxhbmVzX2VuYWJsZSB8
PSAoMSA8PCBpKTsNCj4gPiArCX0NCj4gPiArDQo+ID4gKwlmb3IgKGkgPSAwOyBpIDwgc2MtPmxh
bmVzOyBpKyspIHsNCj4gPiArCQlrc2VyZGVzX3JlbGVhc2VfcmVzZXQoc2MsIGkpOw0KPiA+ICsN
Cj4gPiArCQlpZiAoc2MtPmxhbmVbaV0ubG9vcGJhY2spDQo+ID4gKwkJCV9rc2VyZGVzX3NldF9s
YW5lX2xvb3BiYWNrKHNjLT5yZWdzLCBpLCBzYy0+bGlua19yYXRlKTsNCj4gPiArCX0NCj4gPiAr
DQo+ID4gKwlyZXQgPSBrc2VyZGVzX2dldF9zdGF0dXMoc2MpOw0KPiA+ICsJaWYgKHJldCkNCj4g
PiArCQlyZXR1cm4gcmV0Ow0KPiA+ICsJZWxzZQ0KPiA+ICsJCXJldHVybiBsYW5lc19lbmFibGU7
DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQga3NlcmRlc19wY2llX2luaXQoc3RydWN0
IGtzZXJkZXNfY29uZmlnICpzYykNCj4gPiArew0KPiA+ICsJaWYgKChzYy0+Y2xrX3JhdGUgIT0g
S1NFUkRFU19DTE9DS19SQVRFXzEwME0pIHx8DQo+ID4gKwkgICAgKHNjLT5saW5rX3JhdGUgIT0g
S1NFUkRFU19MSU5LX1JBVEVfNUcpKQ0KPiA+ICsJCXJldHVybiAtRUlOVkFMOw0KPiA+ICsNCj4g
PiArCXJldHVybiBrc2VyZGVzX2xvYWRfaW5pdF9mdyhzYywga3MyX3BjaWVfc2VyZGVzX2Zpcm13
YXJlcywNCj4gPiArCQkJCSAgICBBUlJBWV9TSVpFKGtzMl9wY2llX3NlcmRlc19maXJtd2FyZXMp
KTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQga3NlcmRlc19zaG93X2Z3X2NvbmZp
ZyhzdHJ1Y3Qga3NlcmRlc19jb25maWcgKnNjKQ0KPiA+ICt7DQo+ID4gKwlzdHJ1Y3Qga3NlcmRl
c19md19jb25maWcgKmZ3ID0gJnNjLT5mdzsNCj4gPiArDQo+ID4gKwlkZXZfaW5mbyhzYy0+ZGV2
LCAiZncgY29uZmlnczpcbiIpOw0KPiA+ICsJZGV2X2luZm8oc2MtPmRldiwgIiAgbGFuZV9jb25m
aWdzOiAweCUwMngsIDB4JTAyeFxuIiwNCj4gPiArCQkgZnctPmxhbmVfY29uZmlnWzBdLCBmdy0+
bGFuZV9jb25maWdbMV0pOw0KPiA+ICsJZGV2X2luZm8oc2MtPmRldiwNCj4gPiArCQkgIiAgbG5r
X2xvc3Nfd2FpdDogJWQsIGxhbmVfc2VlZHM6IDB4JTA4eCwgZmFzdF90cmFpbjoNCj4gMHglMDh4
XG4iLA0KPiA+ICsJCSBmdy0+bGlua19sb3NzX3dhaXQsIGZ3LT5sYW5lX3NlZWRzLCBmdy0+ZmFz
dF90cmFpbik7DQo+IA0KPiBUaGlzIGxvb2tzIG1vcmUgbGlrZSBhIGRlYnVnIGZlYXR1cmUuIExl
dHMgdXNlIGRlYnVnZnMgZm9yIGl0Lg0KDQp3ZSB3aWxsIGRyb3AgdGhpcyBmb3Igbm93IGFuZCBh
ZGQgZGVidWdmcyBhcyBhIHNlcGFyYXRlDQpmZWF0dXJlIGxhdGVyIGluIGFub3RoZXIgcGF0Y2gN
Cg0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBrc2VyZGVzX3Nob3dfbGFuZV9jb25m
aWcoc3RydWN0IGRldmljZSAqZGV2LA0KPiA+ICsJCQkJICAgICBzdHJ1Y3Qga3NlcmRlc19sYW5l
X2NvbmZpZyAqbGMpDQo+ID4gK3sNCj4gPiArCWRldl9pbmZvKGRldiwgIiVzXG4iLCBsYy0+ZW5h
YmxlID8gImVuYWJsZSIgOiAiZGlzYWJsZSIpOw0KPiA+ICsJZGV2X2luZm8oZGV2LCAiY3RybF9y
YXRlIDB4JXhcbiIsIGxjLT5jdHJsX3JhdGUpOw0KPiA+ICsJZGV2X2luZm8oZGV2LCAicnhfc3Rh
cnQgJXUgJXVcbiIsDQo+ID4gKwkJIGxjLT5yeF9zdGFydC5hdHQsIGxjLT5yeF9zdGFydC5ib29z
dCk7DQo+ID4gKwlkZXZfaW5mbyhkZXYsICJyeF9mb3JjZSAldSAldVxuIiwNCj4gPiArCQkgbGMt
PnJ4X2ZvcmNlLmF0dCwgbGMtPnJ4X2ZvcmNlLmJvb3N0KTsNCj4gPiArCWRldl9pbmZvKGRldiwg
InR4X2NvZWZmICV1ICV1ICV1ICV1ICV1XG4iLA0KPiA+ICsJCSBsYy0+dHhfY29lZmYuYzEsIGxj
LT50eF9jb2VmZi5jMiwgbGMtPnR4X2NvZWZmLmNtLA0KPiA+ICsJCSBsYy0+dHhfY29lZmYuYXR0
LCBsYy0+dHhfY29lZmYudnJlZyk7DQo+ID4gKwlkZXZfaW5mbyhkZXYsICJsb29wYmFjayAldVxu
IiwgbGMtPmxvb3BiYWNrKTsNCj4gDQo+IHNhbWUgaGVyZS4NCg0KdGhpcyB0b28sIHdpbGwgYmUg
YSBzZXBhcmF0ZSBmZWF0dXJlIGxhdGVyIGluIGFub3RoZXIgcGF0Y2gNCg0KPiA+ICt9DQo+ID4g
Kw0KPiA+ICtzdGF0aWMgdm9pZCBrc2VyZGVzX3Nob3dfY29uZmlnKHN0cnVjdCBrc2VyZGVzX2Nv
bmZpZyAqc2MpDQo+ID4gK3sNCj4gPiArCXUzMiBpOw0KPiA+ICsNCj4gPiArCWlmICghc2MtPmRl
YnVnKQ0KPiA+ICsJCXJldHVybjsNCj4gPiArDQo+ID4gKwlkZXZfaW5mbyhzYy0+ZGV2LCAic2Vy
ZGVzIHJlZ3MgMHglcFxuIiwgc2MtPnJlZ3MpOw0KPiA+ICsJaWYgKHNjLT5wZXJpcGhlcmFsX3Jl
Z21hcCkNCj4gPiArCQlkZXZfaW5mbyhzYy0+ZGV2LCAicGVyaXBoZXJhbCByZWdtYXAgaGFuZGxl
IGRlZmluZWRcbiIpOw0KPiA+ICsJZGV2X2luZm8oc2MtPmRldiwgInBoeV90eXBlICV1XG4iLCBz
Yy0+cGh5X3R5cGUpOw0KPiA+ICsJZGV2X2luZm8oc2MtPmRldiwgImNsa19yYXRlICV1XG4iLCBz
Yy0+Y2xrX3JhdGUpOw0KPiA+ICsJZGV2X2luZm8oc2MtPmRldiwgImxpbmtfcmF0ZSAldVxuIiwg
c2MtPmxpbmtfcmF0ZSk7DQo+ID4gKwlkZXZfaW5mbyhzYy0+ZGV2LCAibGFuZXMgJXVcbiIsIHNj
LT5sYW5lcyk7DQo+ID4gKwlpZiAoKHNjLT5waHlfdHlwZSA9PSBLU0VSREVTX1BIWV9YR0UpICYm
IHNjLT5wY3NyX3JlZ21hcCkNCj4gPiArCQlkZXZfaW5mbyhzYy0+ZGV2LCAicGNzciByZWdtYXAg
aGFuZGxlIGRlZmluZWRcbiIpOw0KPiA+ICsNCj4gPiArCWlmIChzYy0+ZmlybXdhcmUpIHsNCj4g
PiArCQlrc2VyZGVzX3Nob3dfZndfY29uZmlnKHNjKTsNCj4gPiArCQlyZXR1cm47DQo+ID4gKwl9
IGVsc2UgaWYgKHNjLT5pbml0X2Z3KSB7DQo+ID4gKwkJZGV2X2luZm8oc2MtPmRldiwgImluaXQg
Znc6ICVzXG4iLCBzYy0+aW5pdF9mdyk7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJZGV2X2luZm8o
c2MtPmRldiwgInJ4LWZvcmNlLSVzXG4iLA0KPiA+ICsJCSAoc2MtPnJ4X2ZvcmNlX2VuYWJsZSA/
ICJlbmFibGUiIDogImRpc2FibGUiKSk7DQo+ID4gKw0KPiA+ICsJZm9yIChpID0gMDsgaSA8IHNj
LT5sYW5lczsgaSsrKSB7DQo+ID4gKwkJZGV2X2luZm8oc2MtPmRldiwgImxhbmVbJXVdOlxuIiwg
aSk7DQo+ID4gKwkJa3NlcmRlc19zaG93X2xhbmVfY29uZmlnKHNjLT5kZXYsICZzYy0+bGFuZVtp
XSk7DQo+ID4gKwl9DQo+IGhlcmUgdG9vLg0KDQp0aGlzIGFsc28sIHdpbGwgYmUgYSBzZXBhcmF0
ZSBmZWF0dXJlIGxhdGVyIGluIGFub3RoZXIgcGF0Y2gNCg0KPiANCj4gPiArfQ0KPiA+ICsNCj4g
PiArc3RhdGljIGludCBrc2VyZGVzX2xhbmVzX2VuYWJsZShzdHJ1Y3Qga3NlcmRlc19jb25maWcg
KnNjKQ0KPiA+ICt7DQo+ID4gKwlpbnQgcmV0ID0gLUVJTlZBTDsNCj4gPiArDQo+ID4gKwlpZiAo
c2MtPnBoeV90eXBlID09IEtTRVJERVNfUEhZX1NHTUlJKQ0KPiA+ICsJCXJldCA9IGtzZXJkZXNf
c2dtaWlfbGFuZXNfZW5hYmxlKHNjKTsNCj4gPiArCWVsc2UgaWYgKHNjLT5waHlfdHlwZSA9PSBL
U0VSREVTX1BIWV9YR0UpDQo+ID4gKwkJcmV0ID0ga3NlcmRlc194Z2VfbGFuZXNfZW5hYmxlKHNj
KTsNCj4gPiArCWVsc2UgaWYgKHNjLT5waHlfdHlwZSA9PSBLU0VSREVTX1BIWV9QQ0lFKQ0KPiA+
ICsJCXJldCA9IGtzZXJkZXNfcGNpZV9sYW5lc19lbmFibGUoc2MpOw0KPiANCj4gc3dpdGNoIGNh
c2UgaGVyZT8NCg0Kd2lsbCBjaGFuZ2UNCg0KPiA+ICsNCj4gPiArCXJldHVybiByZXQ7DQo+ID4g
K30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQga3NlcmRlc19pbml0KHN0cnVjdCBwaHkgKnBoeSkN
Cj4gPiArew0KPiA+ICsJc3RydWN0IGtzZXJkZXNfZGV2ICpzZCA9IHBoeV9nZXRfZHJ2ZGF0YShw
aHkpOw0KPiA+ICsJc3RydWN0IGtzZXJkZXNfY29uZmlnICpzYyA9ICZzZC0+c2M7DQo+ID4gKwlp
bnQgcmV0Ow0KPiA+ICsNCj4gPiArCWlmIChzYy0+cGh5X3R5cGUgPT0gS1NFUkRFU19QSFlfU0dN
SUkpDQo+ID4gKwkJcmV0ID0ga3NlcmRlc19zZ21paV9pbml0KHNjKTsNCj4gPiArCWVsc2UgaWYg
KHNjLT5waHlfdHlwZSA9PSBLU0VSREVTX1BIWV9YR0UpDQo+ID4gKwkJcmV0ID0ga3NlcmRlc194
Z2VfaW5pdChzYyk7DQo+ID4gKwllbHNlIGlmIChzYy0+cGh5X3R5cGUgPT0gS1NFUkRFU19QSFlf
UENJRSkNCj4gPiArCQlyZXQgPSBrc2VyZGVzX3BjaWVfaW5pdChzYyk7DQo+ID4gKwllbHNlDQo+
ID4gKwkJcmV0ID0gLUVJTlZBTDsNCj4gDQo+IHVzZSBzd2l0Y2ggY2FzZSBpbnN0ZWFkLg0KDQp3
aWxsIGNoYW5nZQ0KDQo+ID4gKw0KPiA+ICsJaWYgKHJldCA8IDApIHsNCj4gPiArCQlkZXZfZXJy
KHNkLT5kZXYsICJzZXJkZXMgaW5pdGlhbGl6YXRpb24gZmFpbGVkICVkXG4iLCByZXQpOw0KPiA+
ICsJCWdvdG8gZG9uZTsNCj4gPiArCX0NCj4gPiArDQo+ID4gKwlyZXQgPSBrc2VyZGVzX2xhbmVz
X2VuYWJsZShzYyk7DQo+ID4gKwlpZiAocmV0IDwgMCkgew0KPiA+ICsJCWRldl9lcnIoc2QtPmRl
diwgInNlcmRlcyBsYW5lcyBlbmFibGUgZmFpbGVkOiAlZFxuIiwgcmV0KTsNCj4gPiArCQlnb3Rv
IGRvbmU7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJZGV2X2luZm8oc2QtPmRldiwgInNlcmRlcyBj
b25maWcgZG9uZSBsYW5lcyhtYXNrKSAweCV4XG4iLCByZXQpOw0KPiANCj4gZGV2X2RiZz8NCg0K
d2lsbCBjaGFuZ2UNCg0KPiA+ICsNCj4gPiArZG9uZToNCj4gPiArCXJldHVybiByZXQ7DQo+ID4g
K30NCj4gPiArDQo+ID4gK3N0cnVjdCBwaHkgKmtzZXJkZXNfcGh5X3hsYXRlKHN0cnVjdCBkZXZp
Y2UgKmRldiwgc3RydWN0IG9mX3BoYW5kbGVfYXJncw0KPiAqYXJncykNCj4gPiArew0KPiA+ICsJ
c3RydWN0IGtzZXJkZXNfZGV2ICpzZCA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOw0KPiANCj4gV2h5
IG5vdCB1c2UgdGhlIGRlZmF1bHQgeGxhdGUgcHJvdmlkZWQgYnkgcGh5LWNvcmU/IHhsYXRlcyBz
aG91bGQgb25seQ0KPiBiZSBkZWZpbmVkIGlmIHRoZSBkcml2ZXIgaGFzIHRvIHVzZSBhcmd1bWVu
dHMgcHJvdmlkZWQgaW4gdGhlIFBIWQ0KPiBzcGVjaWZpZXIuDQoNCndpbGwgaW52ZXN0aWdhdGUN
Cg0KPiA+ICsNCj4gPiArCXJldHVybiBzZC0+cGh5Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0
aWMgaW50IGtzZXJkZXNfZ2V0X2xhbmVfYmluZGluZ3Moc3RydWN0IGRldmljZSAqZGV2LA0KPiA+
ICsJCQkJICAgICBzdHJ1Y3QgZGV2aWNlX25vZGUgKm5wLA0KPiA+ICsJCQkJICAgICBzdHJ1Y3Qg
a3NlcmRlc19sYW5lX2NvbmZpZyAqbGMpDQo+ID4gK3sNCj4gPiArCXN0cnVjdCBrc2VyZGVzX2Vx
dWFsaXplciAqZXE7DQo+ID4gKwlzdHJ1Y3Qga3NlcmRlc190eF9jb2VmZiAqdGM7DQo+ID4gKw0K
PiA+ICsJaWYgKG9mX2ZpbmRfcHJvcGVydHkobnAsICJkaXNhYmxlIiwgTlVMTCkpDQo+ID4gKwkJ
bGMtPmVuYWJsZSA9IDA7DQo+ID4gKwllbHNlDQo+ID4gKwkJbGMtPmVuYWJsZSA9IDE7DQo+ID4g
Kw0KPiA+ICsJZGV2X2RiZyhkZXYsICJsYW5lIGVuYWJsZTogJWRcbiIsIGxjLT5lbmFibGUpOw0K
PiA+ICsNCj4gPiArCWlmIChvZl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgImNvbnRyb2wtcmF0ZSIs
ICZsYy0+Y3RybF9yYXRlKSkgew0KPiA+ICsJCWRldl9pbmZvKGRldiwgInVzZSBkZWZhdWx0IGxh
bmUgY29udHJvbC1yYXRlOiAldVxuIiwNCj4gPiArCQkJIGxjLT5jdHJsX3JhdGUpOw0KPiA+ICsJ
fQ0KPiA+ICsJZGV2X2RiZyhkZXYsICJsYW5lIGNvbnRyb2wtcmF0ZTogJWRcbiIsIGxjLT5jdHJs
X3JhdGUpOw0KPiA+ICsNCj4gPiArCWlmIChvZl9maW5kX3Byb3BlcnR5KG5wLCAibG9vcGJhY2si
LCBOVUxMKSkNCj4gPiArCQlsYy0+bG9vcGJhY2sgPSAxOw0KPiA+ICsJZWxzZQ0KPiA+ICsJCWxj
LT5sb29wYmFjayA9IDA7DQo+ID4gKw0KPiA+ICsJZGV2X2RiZyhkZXYsICJsYW5lIGxvb3BiYWNr
OiAlZFxuIiwgbGMtPmxvb3BiYWNrKTsNCj4gPiArDQo+ID4gKwllcSA9ICZsYy0+cnhfc3RhcnQ7
DQo+ID4gKwlpZiAob2ZfcHJvcGVydHlfcmVhZF91MzJfYXJyYXkobnAsICJyeC1zdGFydCIsICZl
cS0+YXR0LCAyKSkgew0KPiA+ICsJCWRldl9pbmZvKGRldiwgInVzZSBkZWZhdWx0IGxhbmUgcngt
c3RhcnQgMCAwXG4iKTsNCj4gPiArCQllcS0+YXR0ID0gMDsNCj4gPiArCQllcS0+Ym9vc3QgPSAw
Ow0KPiA+ICsJfQ0KPiA+ICsJZGV2X2RiZyhkZXYsICJsYW5lIHJ4LXN0YXJ0OiAlZCAlZFxuIiwg
ZXEtPmF0dCwgZXEtPmJvb3N0KTsNCj4gPiArDQo+ID4gKwllcSA9ICZsYy0+cnhfZm9yY2U7DQo+
ID4gKwlpZiAob2ZfcHJvcGVydHlfcmVhZF91MzJfYXJyYXkobnAsICJyeC1mb3JjZSIsICZlcS0+
YXR0LCAyKSkgew0KPiA+ICsJCWRldl9pbmZvKGRldiwgInVzZSBkZWZhdWx0IGxhbmUgcngtZm9y
Y2UgMCAwXG4iKTsNCj4gPiArCQllcS0+YXR0ID0gMDsNCj4gPiArCQllcS0+Ym9vc3QgPSAwOw0K
PiA+ICsJfQ0KPiA+ICsJZGV2X2RiZyhkZXYsICJsYW5lIHJ4LWZvcmNlOiAlZCAlZFxuIiwgZXEt
PmF0dCwgZXEtPmJvb3N0KTsNCj4gPiArDQo+ID4gKwl0YyA9ICZsYy0+dHhfY29lZmY7DQo+ID4g
KwlpZiAob2ZfcHJvcGVydHlfcmVhZF91MzJfYXJyYXkobnAsICJ0eC1jb2VmZiIsICZ0Yy0+YzEs
IDUpKSB7DQo+ID4gKwkJZGV2X2luZm8oZGV2LCAidXNlIGRlZmF1bHQgdHgtY29lZmYgMFxuIik7
DQo+ID4gKwkJdGMtPmMxID0gMDsNCj4gPiArCX0NCj4gPiArCWRldl9kYmcoZGV2LCAidHgtY29l
ZmY6ICVkICVkICVkICVkICVkXG4iLA0KPiA+ICsJCXRjLT5jMSwgdGMtPmMyLCB0Yy0+Y20sIHRj
LT5hdHQsIHRjLT52cmVnKTsNCj4gPiArDQo+ID4gKwlyZXR1cm4gMDsNCj4gPiArfQ0KPiA+ICsN
Cj4gPiArc3RhdGljIHZvaWQga3NlcmRlc19zZXRfc2dtaWlfZGVmYXVsdHMoc3RydWN0IGtzZXJk
ZXNfY29uZmlnICpzYykNCj4gPiArew0KPiA+ICsJaW50IGk7DQo+ID4gKw0KPiA+ICsJc2MtPmNs
a19yYXRlCQk9IEtTRVJERVNfQ0xPQ0tfUkFURV8xNTZQMjVNOw0KPiA+ICsJc2MtPmxpbmtfcmF0
ZQkJPSBLU0VSREVTX0xJTktfUkFURV8xUDI1RzsNCj4gPiArCXNjLT5sYW5lcwkJPSA0Ow0KPiA+
ICsJc2MtPnJ4X2ZvcmNlX2VuYWJsZQk9IDA7DQo+ID4gKw0KPiA+ICsJZm9yIChpID0gMDsgaSA8
IHNjLT5sYW5lczsgaSsrKSB7DQo+ID4gKwkJbWVtc2V0KCZzYy0+bGFuZVtpXSwgMCwgc2l6ZW9m
KHNjLT5sYW5lW2ldKSk7DQo+ID4gKwkJc2MtPmxhbmVbaV0uY3RybF9yYXRlID0gS1NFUkRFU19R
VUFSVEVSX1JBVEU7DQo+ID4gKwl9DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGtz
ZXJkZXNfc2V0X3hnZV9kZWZhdWx0cyhzdHJ1Y3Qga3NlcmRlc19jb25maWcgKnNjKQ0KPiA+ICt7
DQo+ID4gKwlpbnQgaTsNCj4gPiArDQo+ID4gKwlzYy0+Y2xrX3JhdGUJCT0gS1NFUkRFU19DTE9D
S19SQVRFXzE1NlAyNU07DQo+ID4gKwlzYy0+bGlua19yYXRlCQk9IEtTRVJERVNfTElOS19SQVRF
XzEwUDMxMjVHOw0KPiA+ICsJc2MtPmxhbmVzCQk9IDI7DQo+ID4gKwlzYy0+cnhfZm9yY2VfZW5h
YmxlCT0gMDsNCj4gPiArDQo+ID4gKwlmb3IgKGkgPSAwOyBpIDwgc2MtPmxhbmVzOyBpKyspIHsN
Cj4gPiArCQltZW1zZXQoJnNjLT5sYW5lW2ldLCAwLCBzaXplb2Yoc2MtPmxhbmVbaV0pKTsNCj4g
PiArCQlzYy0+bGFuZVtpXS5jdHJsX3JhdGUgPSBLU0VSREVTX0ZVTExfUkFURTsNCj4gPiArCX0N
Cj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQga3NlcmRlc19zZXRfcGNpZV9kZWZhdWx0
cyhzdHJ1Y3Qga3NlcmRlc19jb25maWcgKnNjKQ0KPiA+ICt7DQo+ID4gKwlpbnQgaTsNCj4gPiAr
DQo+ID4gKwlzYy0+Y2xrX3JhdGUJCT0gS1NFUkRFU19DTE9DS19SQVRFXzEwME07DQo+ID4gKwlz
Yy0+bGlua19yYXRlCQk9IEtTRVJERVNfTElOS19SQVRFXzVHOw0KPiA+ICsJc2MtPmxhbmVzCQk9
IDI7DQo+ID4gKwlzYy0+cnhfZm9yY2VfZW5hYmxlCT0gMDsNCj4gPiArDQo+ID4gKwlmb3IgKGkg
PSAwOyBpIDwgc2MtPmxhbmVzOyBpKyspDQo+ID4gKwkJbWVtc2V0KCZzYy0+bGFuZVtpXSwgMCwg
c2l6ZW9mKHNjLT5sYW5lW2ldKSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGtz
ZXJkZXNfc2V0X2RlZmF1bHRzKHN0cnVjdCBrc2VyZGVzX2NvbmZpZyAqc2MsDQo+ID4gKwkJCQkg
ZW51bSBLU0VSREVTX1BIWV9UWVBFIHBoeV90eXBlKQ0KPiA+ICt7DQo+ID4gKwlzd2l0Y2ggKHBo
eV90eXBlKSB7DQo+ID4gKwljYXNlIEtTRVJERVNfUEhZX1NHTUlJOg0KPiA+ICsJCWtzZXJkZXNf
c2V0X3NnbWlpX2RlZmF1bHRzKHNjKTsNCj4gPiArCQlicmVhazsNCj4gPiArCWNhc2UgS1NFUkRF
U19QSFlfWEdFOg0KPiA+ICsJCWtzZXJkZXNfc2V0X3hnZV9kZWZhdWx0cyhzYyk7DQo+ID4gKwkJ
YnJlYWs7DQo+ID4gKwljYXNlIEtTRVJERVNfUEhZX1BDSUU6DQo+ID4gKwkJa3NlcmRlc19zZXRf
cGNpZV9kZWZhdWx0cyhzYyk7DQo+ID4gKwkJYnJlYWs7DQo+ID4gKwlkZWZhdWx0Og0KPiA+ICsJ
CWJyZWFrOw0KPiA+ICsJfQ0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IGtzZXJkZXNf
Z2V0X3Byb3BlcnRpZXMoc3RydWN0IGtzZXJkZXNfZGV2ICpzZCwNCj4gPiArCQkJCSAgc3RydWN0
IGRldmljZV9ub2RlICpucCkNCj4gDQo+IGtzZXJkZXNfb2ZfcGFyc2U/DQoNCndpbGwgcmVuYW1l
DQoNCj4gPiArew0KPiA+ICsJc3RydWN0IGtzZXJkZXNfY29uZmlnICpzYyA9ICZzZC0+c2M7DQo+
ID4gKwlzdHJ1Y3QgZGV2aWNlX25vZGUgKmxwOw0KPiA+ICsJc3RydWN0IGRldmljZSAqZGV2ID0g
c2QtPmRldjsNCj4gPiArCXN0cnVjdCByZXNvdXJjZSByZXM7DQo+ID4gKwl2b2lkIF9faW9tZW0g
KnJlZ3M7DQo+ID4gKwljb25zdCBjaGFyICpwaHlfdHlwZTsNCj4gPiArCWNoYXIgbmFtZVsxNl0g
PSB7J2wnLCAnYScsICduJywgJ2UnfTsNCj4gPiArCWludCByZXQsIGk7DQo+ID4gKw0KPiA+ICsJ
cmV0ID0gb2ZfYWRkcmVzc190b19yZXNvdXJjZShucCwgU0VSREVTX1JFR19JTkRFWCwgJnJlcyk7
DQo+ID4gKwlpZiAocmV0KSB7DQo+ID4gKwkJZGV2X2VycihkZXYsICJDYW4ndCB4bGF0ZSBzZXJk
ZXMgcmVnIGFkZHIgb2Ygbm9kZSglcylcbiIsDQo+ID4gKwkJCW5wLT5uYW1lKTsNCj4gPiArCQly
ZXR1cm4gcmV0Ow0KPiA+ICsJfQ0KPiA+ICsNCj4gPiArCXJlZ3MgPSBkZXZtX2lvcmVtYXBfcmVz
b3VyY2UoZGV2LCAmcmVzKTsNCj4gPiArCWlmIChJU19FUlIocmVncykpIHsNCj4gPiArCQlkZXZf
ZXJyKGRldiwgIkZhaWxlZCB0byBtYXAgc2VyZGVzIHJlZ2lzdGVyIGJhc2VcbiIpOw0KPiA+ICsJ
CXJldHVybiBQVFJfRVJSKHJlZ3MpOw0KPiA+ICsJfQ0KPiA+ICsJc2MtPnJlZ3MgPSByZWdzOw0K
PiA+ICsNCj4gPiArCXJldCA9IG9mX3Byb3BlcnR5X3JlYWRfc3RyaW5nKG5wLCAicGh5LXR5cGUi
LCAmcGh5X3R5cGUpOw0KPiANCj4gdXNlIGNvbXBhdGlibGUgcHJvcGVydHkgZm9yIHRoaXMuDQoN
CndpbGwgdXBkYXRlIHRvIHVzZSBjb21wYXRpYmxlIHByb3BlcnR5DQoNCj4gPiArCWlmICghcmV0
KSB7DQo+ID4gKwkJaWYgKHN0cmNtcChwaHlfdHlwZSwgInNnbWlpIikgPT0gMCkNCj4gPiArCQkJ
c2MtPnBoeV90eXBlID0gS1NFUkRFU19QSFlfU0dNSUk7DQo+ID4gKwkJZWxzZSBpZiAoc3RyY21w
KHBoeV90eXBlLCAieGdlIikgPT0gMCkNCj4gPiArCQkJc2MtPnBoeV90eXBlID0gS1NFUkRFU19Q
SFlfWEdFOw0KPiA+ICsJCWVsc2UgaWYgKHN0cmNtcChwaHlfdHlwZSwgInBjaWUiKSA9PSAwKQ0K
PiA+ICsJCQlzYy0+cGh5X3R5cGUgPSBLU0VSREVTX1BIWV9QQ0lFOw0KPiA+ICsJCWVsc2UNCj4g
PiArCQkJcmV0dXJuIC1FSU5WQUw7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJc2MtPmRldiA9IGRl
djsNCj4gPiArDQo+ID4gKwkvKiBTZXQgdGhlIGRlZmF1bHRzIGJhc2Ugb24gcGh5IHR5cGUgKi8N
Cj4gPiArCWtzZXJkZXNfc2V0X2RlZmF1bHRzKHNjLCBzYy0+cGh5X3R5cGUpOw0KPiA+ICsNCj4g
PiArCWlmIChvZl9wcm9wZXJ0eV9yZWFkX2Jvb2wobnAsICJzeXNjb24tcGVyaXBoZXJhbCIpKSB7
DQo+ID4gKwkJc2MtPnBlcmlwaGVyYWxfcmVnbWFwID0NCj4gPiArCQkJc3lzY29uX3JlZ21hcF9s
b29rdXBfYnlfcGhhbmRsZShucCwNCj4gPiArCQkJCQkJCSJzeXNjb24tcGVyaXBoZXJhbCIpOw0K
PiA+ICsJCWlmIChJU19FUlIoc2MtPnBlcmlwaGVyYWxfcmVnbWFwKSkgew0KPiA+ICsJCQlkZXZf
ZXJyKHNjLT5kZXYsDQo+ID4gKwkJCQkiZmFpbGVkIHRvIGdldCBzeXNjb24tcGVyaXBoZXJhbCBy
ZWdtYXBcbiIpOw0KPiA+ICsJCQlyZXR1cm4gUFRSX0VSUihzYy0+cGVyaXBoZXJhbF9yZWdtYXAp
Ow0KPiA+ICsJCX0NCj4gPiArCX0NCj4gPiArDQo+ID4gKwlpZiAob2ZfcHJvcGVydHlfcmVhZF9i
b29sKG5wLCAic3lzY29uLWxpbmsiKSkgew0KPiA+ICsJCXNjLT5wY3NyX3JlZ21hcCA9DQo+ID4g
KwkJCXN5c2Nvbl9yZWdtYXBfbG9va3VwX2J5X3BoYW5kbGUobnAsICJzeXNjb24tbGluayIpOw0K
PiA+ICsJCWlmIChJU19FUlIoc2MtPnBjc3JfcmVnbWFwKSkgew0KPiA+ICsJCQlkZXZfZXJyKHNj
LT5kZXYsDQo+ID4gKwkJCQkiZmFpbGVkIHRvIGdldCBzeXNjb24tbGluayByZWdtYXBcbiIpOw0K
PiA+ICsJCQlyZXR1cm4gUFRSX0VSUihzYy0+cGNzcl9yZWdtYXApOw0KPiA+ICsJCX0NCj4gPiAr
CX0NCj4gPiArDQo+ID4gKwlpZiAob2ZfcHJvcGVydHlfcmVhZF91MzIobnAsICJyZWZjbGsta2h6
IiwgJnNjLT5jbGtfcmF0ZSkpDQo+ID4gKwkJZGV2X2luZm8oZGV2LCAidXNlIGRlZmF1bHQgcmVm
Y2xrLWtoejogJXVcbiIsIHNjLT5jbGtfcmF0ZSk7DQo+ID4gKw0KPiA+ICsJaWYgKG9mX3Byb3Bl
cnR5X3JlYWRfdTMyKG5wLCAibGluay1yYXRlLWticHMiLCAmc2MtPmxpbmtfcmF0ZSkpIHsNCj4g
PiArCQlkZXZfaW5mbyhkZXYsICJ1c2UgZGVmYXVsdCBsaW5rLXJhdGUta2JwczogJXVcbiIsDQo+
ID4gKwkJCSBzYy0+bGlua19yYXRlKTsNCj4gPiArCX0NCj4gPiArDQo+ID4gKwlpZiAob2ZfcHJv
cGVydHlfcmVhZF91MzIobnAsICJtYXgtbGFuZXMiLCAmc2MtPmxhbmVzKSkNCj4gPiArCQlkZXZf
aW5mbyhkZXYsICJ1c2UgZGVmYXVsdCBtYXgtbGFuZXMgJWRcbiIsIHNjLT5sYW5lcyk7DQo+ID4g
Kw0KPiA+ICsJaWYgKHNjLT5sYW5lcyA+IEtTRVJERVNfTUFYX0xBTkVTKSB7DQo+ID4gKwkJc2Mt
PmxhbmVzID0gS1NFUkRFU19NQVhfTEFORVM7DQo+ID4gKwkJZGV2X2luZm8oZGV2LCAidXNlIG1h
eCBhbGxvd2VkIGxhbmVzICVkXG4iLCBzYy0+bGFuZXMpOw0KPiA+ICsJfQ0KPiA+ICsNCj4gPiAr
CXNjLT5kZWJ1ZyA9IG9mX3Byb3BlcnR5X3JlYWRfYm9vbChucCwgImRlYnVnIik7DQo+ID4gKw0K
PiA+ICsJaWYgKG9mX2ZpbmRfcHJvcGVydHkobnAsICJyeC1mb3JjZS1lbmFibGUiLCBOVUxMKSkN
Cj4gPiArCQlzYy0+cnhfZm9yY2VfZW5hYmxlID0gMTsNCj4gPiArCWVsc2UNCj4gPiArCQlzYy0+
cnhfZm9yY2VfZW5hYmxlID0gMDsNCj4gPiArDQo+ID4gKwlmb3IgKGkgPSAwOyBpIDwgc2MtPmxh
bmVzOyBpKyspIHsNCj4gPiArCQlzcHJpbnRmKCZuYW1lWzRdLCAiJWQiLCBpKTsNCj4gPiArCQls
cCA9IG9mX2ZpbmRfbm9kZV9ieV9uYW1lKG5wLCBuYW1lKTsNCj4gPiArCQlpZiAobHApIHsNCj4g
PiArCQkJaWYgKGtzZXJkZXNfZ2V0X2xhbmVfYmluZGluZ3MoZGV2LCBscCwgJnNjLT5sYW5lW2ld
KSkNCj4gPiArCQkJCXJldHVybiAtRUlOVkFMOw0KPiA+ICsJCX0NCj4gPiArCX0NCj4gPiArDQo+
ID4gKwlyZXR1cm4gMDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHN0cnVjdCBwaHlfb3Bz
IGtzZXJkZXNfb3BzID0gew0KPiA+ICsJLmluaXQJCT0ga3NlcmRlc19pbml0LA0KPiA+ICsJLm93
bmVyCQk9IFRISVNfTU9EVUxFLA0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArc3RhdGljIGludCBrc2Vy
ZGVzX3Byb2JlKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpDQo+ID4gK3sNCj4gPiArCXN0
cnVjdCBwaHlfcHJvdmlkZXIgKnBoeV9wcm92aWRlcjsNCj4gPiArCXN0cnVjdCBrc2VyZGVzX2Rl
diAqc2Q7DQo+ID4gKwlzdHJ1Y3QgZGV2aWNlX25vZGUgKm5wID0gcGRldi0+ZGV2Lm9mX25vZGU7
DQo+ID4gKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSAmcGRldi0+ZGV2Ow0KPiA+ICsJaW50IHJldDsN
Cj4gPiArDQo+ID4gKwlzZCA9IGRldm1fa3phbGxvYyhkZXYsIHNpemVvZigqc2QpLCBHRlBfS0VS
TkVMKTsNCj4gPiArCWlmICghc2QpDQo+ID4gKwkJcmV0dXJuIC1FTk9NRU07DQo+ID4gKw0KPiA+
ICsJc2QtPmRldiA9IGRldjsNCj4gPiArDQo+ID4gKwlyZXQgPSBrc2VyZGVzX2dldF9wcm9wZXJ0
aWVzKHNkLCBucCk7DQo+ID4gKwlpZiAocmV0KQ0KPiA+ICsJCXJldHVybiByZXQ7DQo+ID4gKw0K
PiA+ICsJa3NlcmRlc19zaG93X2NvbmZpZygmc2QtPnNjKTsNCj4gPiArDQo+ID4gKwlkZXZfc2V0
X2RydmRhdGEoZGV2LCBzZCk7DQo+ID4gKwlzZC0+cGh5ID0gZGV2bV9waHlfY3JlYXRlKGRldiwg
TlVMTCwgJmtzZXJkZXNfb3BzKTsNCj4gPiArCWlmIChJU19FUlIoc2QtPnBoeSkpDQo+ID4gKwkJ
cmV0dXJuIFBUUl9FUlIoc2QtPnBoeSk7DQo+ID4gKw0KPiA+ICsJcGh5X3NldF9kcnZkYXRhKHNk
LT5waHksIHNkKTsNCj4gPiArCXBoeV9wcm92aWRlciA9IGRldm1fb2ZfcGh5X3Byb3ZpZGVyX3Jl
Z2lzdGVyKHNkLT5kZXYsDQo+ID4gKwkJCQkJCSAgICAga3NlcmRlc19waHlfeGxhdGUpOw0KPiA+
ICsNCj4gPiArCWlmIChJU19FUlIocGh5X3Byb3ZpZGVyKSkNCj4gPiArCQlyZXR1cm4gUFRSX0VS
Ul9PUl9aRVJPKHBoeV9wcm92aWRlcik7DQo+ID4gKw0KPiA+ICsJZGV2X2luZm8oJnBkZXYtPmRl
diwgInByb2JlZCIpOw0KPiANCj4gVGhpcyBpcyBub3QgbmVlZGVkLiBNYXliZSBkZXZfdmRiZz8N
Cg0Kd2lsbCBjaGFuZ2UgdG8gZGV2X3ZkYmcNCg0KPiA+ICsJcmV0dXJuIDA7DQo+ID4gK30NCj4g
PiArDQo+ID4gK3N0YXRpYyBjb25zdCBzdHJ1Y3Qgb2ZfZGV2aWNlX2lkIGtzZXJkZXNfb2ZfbWF0
Y2hbXSA9IHsNCj4gPiArCXsgLmNvbXBhdGlibGUgPSAidGksa2V5c3RvbmUtc2VyZGVzLWdiZSIg
fSwNCj4gPiArCXsgLmNvbXBhdGlibGUgPSAidGksa2V5c3RvbmUtc2VyZGVzLXBjaWUiIH0sDQo+
ID4gKwl7IC5jb21wYXRpYmxlID0gInRpLGtleXN0b25lLXNlcmRlcy14Z2JlIiB9LA0KPiA+ICsJ
eyB9LA0KPiA+ICt9Ow0KPiA+ICtNT0RVTEVfREVWSUNFX1RBQkxFKG9mLCBrc2VyZGVzX29mX21h
dGNoKTsNCj4gPiArDQo+ID4gK3N0YXRpYyBzdHJ1Y3QgcGxhdGZvcm1fZHJpdmVyIGtzZXJkZXNf
ZHJpdmVyID0gew0KPiA+ICsJLnByb2JlCT0ga3NlcmRlc19wcm9iZSwNCj4gPiArCS5kcml2ZXIg
PSB7DQo+ID4gKwkJLm9mX21hdGNoX3RhYmxlCT0ga3NlcmRlc19vZl9tYXRjaCwNCj4gPiArCQku
bmFtZSAgPSAidGksa2V5c3RvbmUtc2VyZGVzIiwNCj4gPiArCQkub3duZXIgPSBUSElTX01PRFVM
RSwNCj4gDQo+IC5vd25lciBpcyBub3QgcmVxdWlyZWQuDQoNCndpbGwgcmVtb3ZlDQoNCj4gPiAr
CX0NCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgX19pbml0IGtleXN0b25lX3NlcmRl
c19waHlfaW5pdCh2b2lkKQ0KPiA+ICt7DQo+ID4gKwlyZXR1cm4gcGxhdGZvcm1fZHJpdmVyX3Jl
Z2lzdGVyKCZrc2VyZGVzX2RyaXZlcik7DQo+ID4gK30NCj4gPiArc3Vic3lzX2luaXRjYWxsKGtl
eXN0b25lX3NlcmRlc19waHlfaW5pdCk7DQo+IA0KPiB0aGlzIHNob3VsZCBiZSBtb2R1bGVfaW5p
dC4NCg0Kd2lsbCBpbnZlc3RpZ2F0ZQ0KDQpUaGFua3MsDQpXaW5nTWFuDQo=

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

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

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-13 18:04 [PATCH 0/3] Common SerDes driver for TI's Keystone Platforms WingMan Kwok
2015-10-13 18:04 ` [PATCH 1/3] phy: keystone: serdes driver for gbe 10gbe and pcie WingMan Kwok
2015-10-13 18:33   ` Mark Rutland
2015-10-13 19:52     ` Kwok, WingMan
2015-10-13 22:58   ` Kishon Vijay Abraham I
2015-10-14 15:15     ` Kwok, WingMan
2015-10-13 18:04 ` [PATCH 2/3] PCI: keystone: update to use generic keystone serdes driver WingMan Kwok
2015-10-13 18:04 ` [PATCH 3/3] ARM: keystone: dts: add PCI serdes driver bindings WingMan Kwok
2015-10-13 18:23   ` Murali Karicheri
2015-10-13 20:12     ` Kwok, WingMan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).