xref: /linux/drivers/phy/xilinx/phy-zynqmp.c (revision 7dcb8668aedc5603cba1f2625c6051beff03797d)
14a33bea0SAnurag Kumar Vulisha // SPDX-License-Identifier: GPL-2.0
24a33bea0SAnurag Kumar Vulisha /*
34a33bea0SAnurag Kumar Vulisha  * phy-zynqmp.c - PHY driver for Xilinx ZynqMP GT.
44a33bea0SAnurag Kumar Vulisha  *
54a33bea0SAnurag Kumar Vulisha  * Copyright (C) 2018-2020 Xilinx Inc.
64a33bea0SAnurag Kumar Vulisha  *
74a33bea0SAnurag Kumar Vulisha  * Author: Anurag Kumar Vulisha <anuragku@xilinx.com>
84a33bea0SAnurag Kumar Vulisha  * Author: Subbaraya Sundeep <sundeep.lkml@gmail.com>
94a33bea0SAnurag Kumar Vulisha  * Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
104a33bea0SAnurag Kumar Vulisha  *
11c8481d99SRadhey Shyam Pandey  * This driver is tested for USB, SGMII, SATA and Display Port currently.
12c8481d99SRadhey Shyam Pandey  * PCIe should also work but that is experimental as of now.
134a33bea0SAnurag Kumar Vulisha  */
144a33bea0SAnurag Kumar Vulisha 
154a33bea0SAnurag Kumar Vulisha #include <linux/clk.h>
164a33bea0SAnurag Kumar Vulisha #include <linux/delay.h>
174a33bea0SAnurag Kumar Vulisha #include <linux/io.h>
184a33bea0SAnurag Kumar Vulisha #include <linux/kernel.h>
194a33bea0SAnurag Kumar Vulisha #include <linux/module.h>
204a33bea0SAnurag Kumar Vulisha #include <linux/of.h>
214a33bea0SAnurag Kumar Vulisha #include <linux/phy/phy.h>
224a33bea0SAnurag Kumar Vulisha #include <linux/platform_device.h>
23b3db66f6SPiyush Mehta #include <linux/pm_runtime.h>
244a33bea0SAnurag Kumar Vulisha #include <linux/slab.h>
254a33bea0SAnurag Kumar Vulisha 
264a33bea0SAnurag Kumar Vulisha #include <dt-bindings/phy/phy.h>
274a33bea0SAnurag Kumar Vulisha 
284a33bea0SAnurag Kumar Vulisha /*
294a33bea0SAnurag Kumar Vulisha  * Lane Registers
304a33bea0SAnurag Kumar Vulisha  */
314a33bea0SAnurag Kumar Vulisha 
324a33bea0SAnurag Kumar Vulisha /* TX De-emphasis parameters */
334a33bea0SAnurag Kumar Vulisha #define L0_TX_ANA_TM_18			0x0048
344a33bea0SAnurag Kumar Vulisha #define L0_TX_ANA_TM_118		0x01d8
354a33bea0SAnurag Kumar Vulisha #define L0_TX_ANA_TM_118_FORCE_17_0	BIT(0)
364a33bea0SAnurag Kumar Vulisha 
374a33bea0SAnurag Kumar Vulisha /* DN Resistor calibration code parameters */
384a33bea0SAnurag Kumar Vulisha #define L0_TXPMA_ST_3			0x0b0c
394a33bea0SAnurag Kumar Vulisha #define L0_DN_CALIB_CODE		0x3f
404a33bea0SAnurag Kumar Vulisha 
414a33bea0SAnurag Kumar Vulisha /* PMA control parameters */
424a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45			0x0cb4
434a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_48			0x0cc0
444a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_OVER_DP_MAIN	BIT(0)
454a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_ENABLE_DP_MAIN	BIT(1)
464a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_OVER_DP_POST1	BIT(2)
474a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_ENABLE_DP_POST1	BIT(3)
484a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_OVER_DP_POST2	BIT(4)
494a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_ENABLE_DP_POST2	BIT(5)
504a33bea0SAnurag Kumar Vulisha 
514a33bea0SAnurag Kumar Vulisha /* PCS control parameters */
524a33bea0SAnurag Kumar Vulisha #define L0_TM_DIG_6			0x106c
534a33bea0SAnurag Kumar Vulisha #define L0_TM_DIS_DESCRAMBLE_DECODER	0x0f
544a33bea0SAnurag Kumar Vulisha #define L0_TX_DIG_61			0x00f4
554a33bea0SAnurag Kumar Vulisha #define L0_TM_DISABLE_SCRAMBLE_ENCODER	0x0f
564a33bea0SAnurag Kumar Vulisha 
574a33bea0SAnurag Kumar Vulisha /* PLL Test Mode register parameters */
584a33bea0SAnurag Kumar Vulisha #define L0_TM_PLL_DIG_37		0x2094
594a33bea0SAnurag Kumar Vulisha #define L0_TM_COARSE_CODE_LIMIT		0x10
604a33bea0SAnurag Kumar Vulisha 
614a33bea0SAnurag Kumar Vulisha /* PLL SSC step size offsets */
624a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEPS_0_LSB		0x2368
634a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEPS_1_MSB		0x236c
644a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEP_SIZE_0_LSB	0x2370
654a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEP_SIZE_1		0x2374
664a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEP_SIZE_2		0x2378
674a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEP_SIZE_3_MSB	0x237c
684a33bea0SAnurag Kumar Vulisha #define L0_PLL_STATUS_READ_1		0x23e4
694a33bea0SAnurag Kumar Vulisha 
704a33bea0SAnurag Kumar Vulisha /* SSC step size parameters */
714a33bea0SAnurag Kumar Vulisha #define STEP_SIZE_0_MASK		0xff
724a33bea0SAnurag Kumar Vulisha #define STEP_SIZE_1_MASK		0xff
734a33bea0SAnurag Kumar Vulisha #define STEP_SIZE_2_MASK		0xff
744a33bea0SAnurag Kumar Vulisha #define STEP_SIZE_3_MASK		0x3
754a33bea0SAnurag Kumar Vulisha #define STEP_SIZE_SHIFT			8
764a33bea0SAnurag Kumar Vulisha #define FORCE_STEP_SIZE			0x10
774a33bea0SAnurag Kumar Vulisha #define FORCE_STEPS			0x20
784a33bea0SAnurag Kumar Vulisha #define STEPS_0_MASK			0xff
794a33bea0SAnurag Kumar Vulisha #define STEPS_1_MASK			0x07
804a33bea0SAnurag Kumar Vulisha 
814a33bea0SAnurag Kumar Vulisha /* Reference clock selection parameters */
824a33bea0SAnurag Kumar Vulisha #define L0_Ln_REF_CLK_SEL(n)		(0x2860 + (n) * 4)
834a33bea0SAnurag Kumar Vulisha #define L0_REF_CLK_SEL_MASK		0x8f
844a33bea0SAnurag Kumar Vulisha 
854a33bea0SAnurag Kumar Vulisha /* Calibration digital logic parameters */
864a33bea0SAnurag Kumar Vulisha #define L3_TM_CALIB_DIG19		0xec4c
874a33bea0SAnurag Kumar Vulisha #define L3_CALIB_DONE_STATUS		0xef14
884a33bea0SAnurag Kumar Vulisha #define L3_TM_CALIB_DIG18		0xec48
894a33bea0SAnurag Kumar Vulisha #define L3_TM_CALIB_DIG19_NSW		0x07
904a33bea0SAnurag Kumar Vulisha #define L3_TM_CALIB_DIG18_NSW		0xe0
914a33bea0SAnurag Kumar Vulisha #define L3_TM_OVERRIDE_NSW_CODE         0x20
924a33bea0SAnurag Kumar Vulisha #define L3_CALIB_DONE			0x02
934a33bea0SAnurag Kumar Vulisha #define L3_NSW_SHIFT			5
944a33bea0SAnurag Kumar Vulisha #define L3_NSW_PIPE_SHIFT		4
954a33bea0SAnurag Kumar Vulisha #define L3_NSW_CALIB_SHIFT		3
964a33bea0SAnurag Kumar Vulisha 
974a33bea0SAnurag Kumar Vulisha #define PHY_REG_OFFSET			0x4000
984a33bea0SAnurag Kumar Vulisha 
994a33bea0SAnurag Kumar Vulisha /*
1004a33bea0SAnurag Kumar Vulisha  * Global Registers
1014a33bea0SAnurag Kumar Vulisha  */
1024a33bea0SAnurag Kumar Vulisha 
1034a33bea0SAnurag Kumar Vulisha /* Refclk selection parameters */
1044a33bea0SAnurag Kumar Vulisha #define PLL_REF_SEL(n)			(0x10000 + (n) * 4)
1054a33bea0SAnurag Kumar Vulisha #define PLL_FREQ_MASK			0x1f
1064a33bea0SAnurag Kumar Vulisha #define PLL_STATUS_LOCKED		0x10
1074a33bea0SAnurag Kumar Vulisha 
1084a33bea0SAnurag Kumar Vulisha /* Inter Connect Matrix parameters */
1094a33bea0SAnurag Kumar Vulisha #define ICM_CFG0			0x10010
1104a33bea0SAnurag Kumar Vulisha #define ICM_CFG1			0x10014
1114a33bea0SAnurag Kumar Vulisha #define ICM_CFG0_L0_MASK		0x07
1124a33bea0SAnurag Kumar Vulisha #define ICM_CFG0_L1_MASK		0x70
1134a33bea0SAnurag Kumar Vulisha #define ICM_CFG1_L2_MASK		0x07
1144a33bea0SAnurag Kumar Vulisha #define ICM_CFG2_L3_MASK		0x70
1154a33bea0SAnurag Kumar Vulisha #define ICM_CFG_SHIFT			4
1164a33bea0SAnurag Kumar Vulisha 
1174a33bea0SAnurag Kumar Vulisha /* Inter Connect Matrix allowed protocols */
1184a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_PD			0x0
1194a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_PCIE		0x1
1204a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_SATA		0x2
1214a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_USB		0x3
1224a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_DP			0x4
1234a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_SGMII		0x5
1244a33bea0SAnurag Kumar Vulisha 
1254a33bea0SAnurag Kumar Vulisha /* Test Mode common reset control  parameters */
1264a33bea0SAnurag Kumar Vulisha #define TM_CMN_RST			0x10018
1274a33bea0SAnurag Kumar Vulisha #define TM_CMN_RST_EN			0x1
1284a33bea0SAnurag Kumar Vulisha #define TM_CMN_RST_SET			0x2
1294a33bea0SAnurag Kumar Vulisha #define TM_CMN_RST_MASK			0x3
1304a33bea0SAnurag Kumar Vulisha 
1314a33bea0SAnurag Kumar Vulisha /* Bus width parameters */
1324a33bea0SAnurag Kumar Vulisha #define TX_PROT_BUS_WIDTH		0x10040
1334a33bea0SAnurag Kumar Vulisha #define RX_PROT_BUS_WIDTH		0x10044
1344a33bea0SAnurag Kumar Vulisha #define PROT_BUS_WIDTH_10		0x0
1354a33bea0SAnurag Kumar Vulisha #define PROT_BUS_WIDTH_20		0x1
1364a33bea0SAnurag Kumar Vulisha #define PROT_BUS_WIDTH_40		0x2
13737291f60SRobert Hancock #define PROT_BUS_WIDTH_SHIFT(n)		((n) * 2)
13837291f60SRobert Hancock #define PROT_BUS_WIDTH_MASK(n)		GENMASK((n) * 2 + 1, (n) * 2)
1394a33bea0SAnurag Kumar Vulisha 
1404a33bea0SAnurag Kumar Vulisha /* Number of GT lanes */
1414a33bea0SAnurag Kumar Vulisha #define NUM_LANES			4
1424a33bea0SAnurag Kumar Vulisha 
1434a33bea0SAnurag Kumar Vulisha /* SIOU SATA control register */
1444a33bea0SAnurag Kumar Vulisha #define SATA_CONTROL_OFFSET		0x0100
1454a33bea0SAnurag Kumar Vulisha 
1464a33bea0SAnurag Kumar Vulisha /* Total number of controllers */
1474a33bea0SAnurag Kumar Vulisha #define CONTROLLERS_PER_LANE		5
1484a33bea0SAnurag Kumar Vulisha 
1494a33bea0SAnurag Kumar Vulisha /* Protocol Type parameters */
1504a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_USB0		0  /* USB controller 0 */
1514a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_USB1		1  /* USB controller 1 */
1524a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_SATA_0		2  /* SATA controller lane 0 */
1534a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_SATA_1		3  /* SATA controller lane 1 */
1544a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_PCIE_0		4  /* PCIe controller lane 0 */
1554a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_PCIE_1		5  /* PCIe controller lane 1 */
1564a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_PCIE_2		6  /* PCIe controller lane 2 */
1574a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_PCIE_3		7  /* PCIe controller lane 3 */
1584a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_DP_0		8  /* Display Port controller lane 0 */
1594a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_DP_1		9  /* Display Port controller lane 1 */
1604a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_SGMII0		10 /* Ethernet SGMII controller 0 */
1614a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_SGMII1		11 /* Ethernet SGMII controller 1 */
1624a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_SGMII2		12 /* Ethernet SGMII controller 2 */
1634a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_SGMII3		13 /* Ethernet SGMII controller 3 */
1644a33bea0SAnurag Kumar Vulisha 
1654a33bea0SAnurag Kumar Vulisha /* Timeout values */
1664a33bea0SAnurag Kumar Vulisha #define TIMEOUT_US			1000
1674a33bea0SAnurag Kumar Vulisha 
1684a33bea0SAnurag Kumar Vulisha struct xpsgtr_dev;
1694a33bea0SAnurag Kumar Vulisha 
1704a33bea0SAnurag Kumar Vulisha /**
1714a33bea0SAnurag Kumar Vulisha  * struct xpsgtr_ssc - structure to hold SSC settings for a lane
1724a33bea0SAnurag Kumar Vulisha  * @refclk_rate: PLL reference clock frequency
1734a33bea0SAnurag Kumar Vulisha  * @pll_ref_clk: value to be written to register for corresponding ref clk rate
1744a33bea0SAnurag Kumar Vulisha  * @steps: number of steps of SSC (Spread Spectrum Clock)
1754a33bea0SAnurag Kumar Vulisha  * @step_size: step size of each step
1764a33bea0SAnurag Kumar Vulisha  */
1774a33bea0SAnurag Kumar Vulisha struct xpsgtr_ssc {
1784a33bea0SAnurag Kumar Vulisha 	u32 refclk_rate;
1794a33bea0SAnurag Kumar Vulisha 	u8  pll_ref_clk;
1804a33bea0SAnurag Kumar Vulisha 	u32 steps;
1814a33bea0SAnurag Kumar Vulisha 	u32 step_size;
1824a33bea0SAnurag Kumar Vulisha };
1834a33bea0SAnurag Kumar Vulisha 
1844a33bea0SAnurag Kumar Vulisha /**
1854a33bea0SAnurag Kumar Vulisha  * struct xpsgtr_phy - representation of a lane
1864a33bea0SAnurag Kumar Vulisha  * @phy: pointer to the kernel PHY device
1874a33bea0SAnurag Kumar Vulisha  * @type: controller which uses this lane
1884a33bea0SAnurag Kumar Vulisha  * @lane: lane number
1894a33bea0SAnurag Kumar Vulisha  * @protocol: protocol in which the lane operates
1904a33bea0SAnurag Kumar Vulisha  * @skip_phy_init: skip phy_init() if true
1914a33bea0SAnurag Kumar Vulisha  * @dev: pointer to the xpsgtr_dev instance
1924a33bea0SAnurag Kumar Vulisha  * @refclk: reference clock index
1934a33bea0SAnurag Kumar Vulisha  */
1944a33bea0SAnurag Kumar Vulisha struct xpsgtr_phy {
1954a33bea0SAnurag Kumar Vulisha 	struct phy *phy;
1964a33bea0SAnurag Kumar Vulisha 	u8 type;
1974a33bea0SAnurag Kumar Vulisha 	u8 lane;
1984a33bea0SAnurag Kumar Vulisha 	u8 protocol;
1994a33bea0SAnurag Kumar Vulisha 	bool skip_phy_init;
2004a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *dev;
2014a33bea0SAnurag Kumar Vulisha 	unsigned int refclk;
2024a33bea0SAnurag Kumar Vulisha };
2034a33bea0SAnurag Kumar Vulisha 
2044a33bea0SAnurag Kumar Vulisha /**
2054a33bea0SAnurag Kumar Vulisha  * struct xpsgtr_dev - representation of a ZynMP GT device
2064a33bea0SAnurag Kumar Vulisha  * @dev: pointer to device
2074a33bea0SAnurag Kumar Vulisha  * @serdes: serdes base address
2084a33bea0SAnurag Kumar Vulisha  * @siou: siou base address
2094a33bea0SAnurag Kumar Vulisha  * @gtr_mutex: mutex for locking
2104a33bea0SAnurag Kumar Vulisha  * @phys: PHY lanes
2114a33bea0SAnurag Kumar Vulisha  * @refclk_sscs: spread spectrum settings for the reference clocks
21267097754SManish Narani  * @clk: reference clocks
2134a33bea0SAnurag Kumar Vulisha  * @tx_term_fix: fix for GT issue
2144a33bea0SAnurag Kumar Vulisha  * @saved_icm_cfg0: stored value of ICM CFG0 register
2154a33bea0SAnurag Kumar Vulisha  * @saved_icm_cfg1: stored value of ICM CFG1 register
2164a33bea0SAnurag Kumar Vulisha  */
2174a33bea0SAnurag Kumar Vulisha struct xpsgtr_dev {
2184a33bea0SAnurag Kumar Vulisha 	struct device *dev;
2194a33bea0SAnurag Kumar Vulisha 	void __iomem *serdes;
2204a33bea0SAnurag Kumar Vulisha 	void __iomem *siou;
2214a33bea0SAnurag Kumar Vulisha 	struct mutex gtr_mutex; /* mutex for locking */
2224a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy phys[NUM_LANES];
2234a33bea0SAnurag Kumar Vulisha 	const struct xpsgtr_ssc *refclk_sscs[NUM_LANES];
22467097754SManish Narani 	struct clk *clk[NUM_LANES];
2254a33bea0SAnurag Kumar Vulisha 	bool tx_term_fix;
2264a33bea0SAnurag Kumar Vulisha 	unsigned int saved_icm_cfg0;
2274a33bea0SAnurag Kumar Vulisha 	unsigned int saved_icm_cfg1;
2284a33bea0SAnurag Kumar Vulisha };
2294a33bea0SAnurag Kumar Vulisha 
2304a33bea0SAnurag Kumar Vulisha /*
2314a33bea0SAnurag Kumar Vulisha  * Configuration Data
2324a33bea0SAnurag Kumar Vulisha  */
2334a33bea0SAnurag Kumar Vulisha 
2344a33bea0SAnurag Kumar Vulisha /* lookup table to hold all settings needed for a ref clock frequency */
2354a33bea0SAnurag Kumar Vulisha static const struct xpsgtr_ssc ssc_lookup[] = {
2364a33bea0SAnurag Kumar Vulisha 	{  19200000, 0x05,  608, 264020 },
2374a33bea0SAnurag Kumar Vulisha 	{  20000000, 0x06,  634, 243454 },
2384a33bea0SAnurag Kumar Vulisha 	{  24000000, 0x07,  760, 168973 },
2394a33bea0SAnurag Kumar Vulisha 	{  26000000, 0x08,  824, 143860 },
2404a33bea0SAnurag Kumar Vulisha 	{  27000000, 0x09,  856,  86551 },
2414a33bea0SAnurag Kumar Vulisha 	{  38400000, 0x0a, 1218,  65896 },
2424a33bea0SAnurag Kumar Vulisha 	{  40000000, 0x0b,  634, 243454 },
2434a33bea0SAnurag Kumar Vulisha 	{  52000000, 0x0c,  824, 143860 },
2444a33bea0SAnurag Kumar Vulisha 	{ 100000000, 0x0d, 1058,  87533 },
2454a33bea0SAnurag Kumar Vulisha 	{ 108000000, 0x0e,  856,  86551 },
2464a33bea0SAnurag Kumar Vulisha 	{ 125000000, 0x0f,  992, 119497 },
2474a33bea0SAnurag Kumar Vulisha 	{ 135000000, 0x10, 1070,  55393 },
2484a33bea0SAnurag Kumar Vulisha 	{ 150000000, 0x11,  792, 187091 }
2494a33bea0SAnurag Kumar Vulisha };
2504a33bea0SAnurag Kumar Vulisha 
2514a33bea0SAnurag Kumar Vulisha /*
2524a33bea0SAnurag Kumar Vulisha  * I/O Accessors
2534a33bea0SAnurag Kumar Vulisha  */
2544a33bea0SAnurag Kumar Vulisha 
2554a33bea0SAnurag Kumar Vulisha static inline u32 xpsgtr_read(struct xpsgtr_dev *gtr_dev, u32 reg)
2564a33bea0SAnurag Kumar Vulisha {
2574a33bea0SAnurag Kumar Vulisha 	return readl(gtr_dev->serdes + reg);
2584a33bea0SAnurag Kumar Vulisha }
2594a33bea0SAnurag Kumar Vulisha 
2604a33bea0SAnurag Kumar Vulisha static inline void xpsgtr_write(struct xpsgtr_dev *gtr_dev, u32 reg, u32 value)
2614a33bea0SAnurag Kumar Vulisha {
2624a33bea0SAnurag Kumar Vulisha 	writel(value, gtr_dev->serdes + reg);
2634a33bea0SAnurag Kumar Vulisha }
2644a33bea0SAnurag Kumar Vulisha 
2654a33bea0SAnurag Kumar Vulisha static inline void xpsgtr_clr_set(struct xpsgtr_dev *gtr_dev, u32 reg,
2664a33bea0SAnurag Kumar Vulisha 				  u32 clr, u32 set)
2674a33bea0SAnurag Kumar Vulisha {
2684a33bea0SAnurag Kumar Vulisha 	u32 value = xpsgtr_read(gtr_dev, reg);
2694a33bea0SAnurag Kumar Vulisha 
2704a33bea0SAnurag Kumar Vulisha 	value &= ~clr;
2714a33bea0SAnurag Kumar Vulisha 	value |= set;
2724a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, reg, value);
2734a33bea0SAnurag Kumar Vulisha }
2744a33bea0SAnurag Kumar Vulisha 
2754a33bea0SAnurag Kumar Vulisha static inline u32 xpsgtr_read_phy(struct xpsgtr_phy *gtr_phy, u32 reg)
2764a33bea0SAnurag Kumar Vulisha {
2774a33bea0SAnurag Kumar Vulisha 	void __iomem *addr = gtr_phy->dev->serdes
2784a33bea0SAnurag Kumar Vulisha 			   + gtr_phy->lane * PHY_REG_OFFSET + reg;
2794a33bea0SAnurag Kumar Vulisha 
2804a33bea0SAnurag Kumar Vulisha 	return readl(addr);
2814a33bea0SAnurag Kumar Vulisha }
2824a33bea0SAnurag Kumar Vulisha 
2834a33bea0SAnurag Kumar Vulisha static inline void xpsgtr_write_phy(struct xpsgtr_phy *gtr_phy,
2844a33bea0SAnurag Kumar Vulisha 				    u32 reg, u32 value)
2854a33bea0SAnurag Kumar Vulisha {
2864a33bea0SAnurag Kumar Vulisha 	void __iomem *addr = gtr_phy->dev->serdes
2874a33bea0SAnurag Kumar Vulisha 			   + gtr_phy->lane * PHY_REG_OFFSET + reg;
2884a33bea0SAnurag Kumar Vulisha 
2894a33bea0SAnurag Kumar Vulisha 	writel(value, addr);
2904a33bea0SAnurag Kumar Vulisha }
2914a33bea0SAnurag Kumar Vulisha 
2924a33bea0SAnurag Kumar Vulisha static inline void xpsgtr_clr_set_phy(struct xpsgtr_phy *gtr_phy,
2934a33bea0SAnurag Kumar Vulisha 				      u32 reg, u32 clr, u32 set)
2944a33bea0SAnurag Kumar Vulisha {
2954a33bea0SAnurag Kumar Vulisha 	void __iomem *addr = gtr_phy->dev->serdes
2964a33bea0SAnurag Kumar Vulisha 			   + gtr_phy->lane * PHY_REG_OFFSET + reg;
2974a33bea0SAnurag Kumar Vulisha 
2984a33bea0SAnurag Kumar Vulisha 	writel((readl(addr) & ~clr) | set, addr);
2994a33bea0SAnurag Kumar Vulisha }
3004a33bea0SAnurag Kumar Vulisha 
3014a33bea0SAnurag Kumar Vulisha /*
3024a33bea0SAnurag Kumar Vulisha  * Hardware Configuration
3034a33bea0SAnurag Kumar Vulisha  */
3044a33bea0SAnurag Kumar Vulisha 
3054a33bea0SAnurag Kumar Vulisha /* Wait for the PLL to lock (with a timeout). */
3064a33bea0SAnurag Kumar Vulisha static int xpsgtr_wait_pll_lock(struct phy *phy)
3074a33bea0SAnurag Kumar Vulisha {
3084a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
3094a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
3104a33bea0SAnurag Kumar Vulisha 	unsigned int timeout = TIMEOUT_US;
3114a33bea0SAnurag Kumar Vulisha 	int ret;
3124a33bea0SAnurag Kumar Vulisha 
3134a33bea0SAnurag Kumar Vulisha 	dev_dbg(gtr_dev->dev, "Waiting for PLL lock\n");
3144a33bea0SAnurag Kumar Vulisha 
3154a33bea0SAnurag Kumar Vulisha 	while (1) {
3164a33bea0SAnurag Kumar Vulisha 		u32 reg = xpsgtr_read_phy(gtr_phy, L0_PLL_STATUS_READ_1);
3174a33bea0SAnurag Kumar Vulisha 
3184a33bea0SAnurag Kumar Vulisha 		if ((reg & PLL_STATUS_LOCKED) == PLL_STATUS_LOCKED) {
3194a33bea0SAnurag Kumar Vulisha 			ret = 0;
3204a33bea0SAnurag Kumar Vulisha 			break;
3214a33bea0SAnurag Kumar Vulisha 		}
3224a33bea0SAnurag Kumar Vulisha 
3234a33bea0SAnurag Kumar Vulisha 		if (--timeout == 0) {
3244a33bea0SAnurag Kumar Vulisha 			ret = -ETIMEDOUT;
3254a33bea0SAnurag Kumar Vulisha 			break;
3264a33bea0SAnurag Kumar Vulisha 		}
3274a33bea0SAnurag Kumar Vulisha 
3284a33bea0SAnurag Kumar Vulisha 		udelay(1);
3294a33bea0SAnurag Kumar Vulisha 	}
3304a33bea0SAnurag Kumar Vulisha 
3314a33bea0SAnurag Kumar Vulisha 	if (ret == -ETIMEDOUT)
3324a33bea0SAnurag Kumar Vulisha 		dev_err(gtr_dev->dev,
3334a33bea0SAnurag Kumar Vulisha 			"lane %u (type %u, protocol %u): PLL lock timeout\n",
3344a33bea0SAnurag Kumar Vulisha 			gtr_phy->lane, gtr_phy->type, gtr_phy->protocol);
3354a33bea0SAnurag Kumar Vulisha 
3364a33bea0SAnurag Kumar Vulisha 	return ret;
3374a33bea0SAnurag Kumar Vulisha }
3384a33bea0SAnurag Kumar Vulisha 
3394a33bea0SAnurag Kumar Vulisha /* Configure PLL and spread-sprectrum clock. */
3404a33bea0SAnurag Kumar Vulisha static void xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy)
3414a33bea0SAnurag Kumar Vulisha {
3424a33bea0SAnurag Kumar Vulisha 	const struct xpsgtr_ssc *ssc;
3434a33bea0SAnurag Kumar Vulisha 	u32 step_size;
3444a33bea0SAnurag Kumar Vulisha 
3454a33bea0SAnurag Kumar Vulisha 	ssc = gtr_phy->dev->refclk_sscs[gtr_phy->refclk];
3464a33bea0SAnurag Kumar Vulisha 	step_size = ssc->step_size;
3474a33bea0SAnurag Kumar Vulisha 
3484a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_phy->dev, PLL_REF_SEL(gtr_phy->lane),
3494a33bea0SAnurag Kumar Vulisha 		       PLL_FREQ_MASK, ssc->pll_ref_clk);
3504a33bea0SAnurag Kumar Vulisha 
3514a33bea0SAnurag Kumar Vulisha 	/* Enable lane clock sharing, if required */
3524a33bea0SAnurag Kumar Vulisha 	if (gtr_phy->refclk != gtr_phy->lane) {
3534a33bea0SAnurag Kumar Vulisha 		/* Lane3 Ref Clock Selection Register */
3544a33bea0SAnurag Kumar Vulisha 		xpsgtr_clr_set(gtr_phy->dev, L0_Ln_REF_CLK_SEL(gtr_phy->lane),
3554a33bea0SAnurag Kumar Vulisha 			       L0_REF_CLK_SEL_MASK, 1 << gtr_phy->refclk);
3564a33bea0SAnurag Kumar Vulisha 	}
3574a33bea0SAnurag Kumar Vulisha 
3584a33bea0SAnurag Kumar Vulisha 	/* SSC step size [7:0] */
3594a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_0_LSB,
3604a33bea0SAnurag Kumar Vulisha 			   STEP_SIZE_0_MASK, step_size & STEP_SIZE_0_MASK);
3614a33bea0SAnurag Kumar Vulisha 
3624a33bea0SAnurag Kumar Vulisha 	/* SSC step size [15:8] */
3634a33bea0SAnurag Kumar Vulisha 	step_size >>= STEP_SIZE_SHIFT;
3644a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_1,
3654a33bea0SAnurag Kumar Vulisha 			   STEP_SIZE_1_MASK, step_size & STEP_SIZE_1_MASK);
3664a33bea0SAnurag Kumar Vulisha 
3674a33bea0SAnurag Kumar Vulisha 	/* SSC step size [23:16] */
3684a33bea0SAnurag Kumar Vulisha 	step_size >>= STEP_SIZE_SHIFT;
3694a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_2,
3704a33bea0SAnurag Kumar Vulisha 			   STEP_SIZE_2_MASK, step_size & STEP_SIZE_2_MASK);
3714a33bea0SAnurag Kumar Vulisha 
3724a33bea0SAnurag Kumar Vulisha 	/* SSC steps [7:0] */
3734a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEPS_0_LSB,
3744a33bea0SAnurag Kumar Vulisha 			   STEPS_0_MASK, ssc->steps & STEPS_0_MASK);
3754a33bea0SAnurag Kumar Vulisha 
3764a33bea0SAnurag Kumar Vulisha 	/* SSC steps [10:8] */
3774a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEPS_1_MSB,
3784a33bea0SAnurag Kumar Vulisha 			   STEPS_1_MASK,
3794a33bea0SAnurag Kumar Vulisha 			   (ssc->steps >> STEP_SIZE_SHIFT) & STEPS_1_MASK);
3804a33bea0SAnurag Kumar Vulisha 
3814a33bea0SAnurag Kumar Vulisha 	/* SSC step size [24:25] */
3824a33bea0SAnurag Kumar Vulisha 	step_size >>= STEP_SIZE_SHIFT;
3834a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_3_MSB,
3844a33bea0SAnurag Kumar Vulisha 			   STEP_SIZE_3_MASK, (step_size & STEP_SIZE_3_MASK) |
3854a33bea0SAnurag Kumar Vulisha 			   FORCE_STEP_SIZE | FORCE_STEPS);
3864a33bea0SAnurag Kumar Vulisha }
3874a33bea0SAnurag Kumar Vulisha 
3884a33bea0SAnurag Kumar Vulisha /* Configure the lane protocol. */
3894a33bea0SAnurag Kumar Vulisha static void xpsgtr_lane_set_protocol(struct xpsgtr_phy *gtr_phy)
3904a33bea0SAnurag Kumar Vulisha {
3914a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
3924a33bea0SAnurag Kumar Vulisha 	u8 protocol = gtr_phy->protocol;
3934a33bea0SAnurag Kumar Vulisha 
3944a33bea0SAnurag Kumar Vulisha 	switch (gtr_phy->lane) {
3954a33bea0SAnurag Kumar Vulisha 	case 0:
3964a33bea0SAnurag Kumar Vulisha 		xpsgtr_clr_set(gtr_dev, ICM_CFG0, ICM_CFG0_L0_MASK, protocol);
3974a33bea0SAnurag Kumar Vulisha 		break;
3984a33bea0SAnurag Kumar Vulisha 	case 1:
3994a33bea0SAnurag Kumar Vulisha 		xpsgtr_clr_set(gtr_dev, ICM_CFG0, ICM_CFG0_L1_MASK,
4004a33bea0SAnurag Kumar Vulisha 			       protocol << ICM_CFG_SHIFT);
4014a33bea0SAnurag Kumar Vulisha 		break;
4024a33bea0SAnurag Kumar Vulisha 	case 2:
4034a33bea0SAnurag Kumar Vulisha 		xpsgtr_clr_set(gtr_dev, ICM_CFG1, ICM_CFG0_L0_MASK, protocol);
4044a33bea0SAnurag Kumar Vulisha 		break;
4054a33bea0SAnurag Kumar Vulisha 	case 3:
4064a33bea0SAnurag Kumar Vulisha 		xpsgtr_clr_set(gtr_dev, ICM_CFG1, ICM_CFG0_L1_MASK,
4074a33bea0SAnurag Kumar Vulisha 			       protocol << ICM_CFG_SHIFT);
4084a33bea0SAnurag Kumar Vulisha 		break;
4094a33bea0SAnurag Kumar Vulisha 	default:
4104a33bea0SAnurag Kumar Vulisha 		/* We already checked 0 <= lane <= 3 */
4114a33bea0SAnurag Kumar Vulisha 		break;
4124a33bea0SAnurag Kumar Vulisha 	}
4134a33bea0SAnurag Kumar Vulisha }
4144a33bea0SAnurag Kumar Vulisha 
4154a33bea0SAnurag Kumar Vulisha /* Bypass (de)scrambler and 8b/10b decoder and encoder. */
4164a33bea0SAnurag Kumar Vulisha static void xpsgtr_bypass_scrambler_8b10b(struct xpsgtr_phy *gtr_phy)
4174a33bea0SAnurag Kumar Vulisha {
4184a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TM_DIG_6, L0_TM_DIS_DESCRAMBLE_DECODER);
4194a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TX_DIG_61, L0_TM_DISABLE_SCRAMBLE_ENCODER);
4204a33bea0SAnurag Kumar Vulisha }
4214a33bea0SAnurag Kumar Vulisha 
4224a33bea0SAnurag Kumar Vulisha /* DP-specific initialization. */
4234a33bea0SAnurag Kumar Vulisha static void xpsgtr_phy_init_dp(struct xpsgtr_phy *gtr_phy)
4244a33bea0SAnurag Kumar Vulisha {
4254a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TXPMD_TM_45,
4264a33bea0SAnurag Kumar Vulisha 			 L0_TXPMD_TM_45_OVER_DP_MAIN |
4274a33bea0SAnurag Kumar Vulisha 			 L0_TXPMD_TM_45_ENABLE_DP_MAIN |
4284a33bea0SAnurag Kumar Vulisha 			 L0_TXPMD_TM_45_OVER_DP_POST1 |
4294a33bea0SAnurag Kumar Vulisha 			 L0_TXPMD_TM_45_OVER_DP_POST2 |
4304a33bea0SAnurag Kumar Vulisha 			 L0_TXPMD_TM_45_ENABLE_DP_POST2);
4314a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TX_ANA_TM_118,
4324a33bea0SAnurag Kumar Vulisha 			 L0_TX_ANA_TM_118_FORCE_17_0);
4334a33bea0SAnurag Kumar Vulisha }
4344a33bea0SAnurag Kumar Vulisha 
4354a33bea0SAnurag Kumar Vulisha /* SATA-specific initialization. */
4364a33bea0SAnurag Kumar Vulisha static void xpsgtr_phy_init_sata(struct xpsgtr_phy *gtr_phy)
4374a33bea0SAnurag Kumar Vulisha {
4384a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
4394a33bea0SAnurag Kumar Vulisha 
4404a33bea0SAnurag Kumar Vulisha 	xpsgtr_bypass_scrambler_8b10b(gtr_phy);
4414a33bea0SAnurag Kumar Vulisha 
4424a33bea0SAnurag Kumar Vulisha 	writel(gtr_phy->lane, gtr_dev->siou + SATA_CONTROL_OFFSET);
4434a33bea0SAnurag Kumar Vulisha }
4444a33bea0SAnurag Kumar Vulisha 
4454a33bea0SAnurag Kumar Vulisha /* SGMII-specific initialization. */
4464a33bea0SAnurag Kumar Vulisha static void xpsgtr_phy_init_sgmii(struct xpsgtr_phy *gtr_phy)
4474a33bea0SAnurag Kumar Vulisha {
4484a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
44937291f60SRobert Hancock 	u32 mask = PROT_BUS_WIDTH_MASK(gtr_phy->lane);
45037291f60SRobert Hancock 	u32 val = PROT_BUS_WIDTH_10 << PROT_BUS_WIDTH_SHIFT(gtr_phy->lane);
4514a33bea0SAnurag Kumar Vulisha 
4524a33bea0SAnurag Kumar Vulisha 	/* Set SGMII protocol TX and RX bus width to 10 bits. */
45337291f60SRobert Hancock 	xpsgtr_clr_set(gtr_dev, TX_PROT_BUS_WIDTH, mask, val);
45437291f60SRobert Hancock 	xpsgtr_clr_set(gtr_dev, RX_PROT_BUS_WIDTH, mask, val);
4554a33bea0SAnurag Kumar Vulisha 
4564a33bea0SAnurag Kumar Vulisha 	xpsgtr_bypass_scrambler_8b10b(gtr_phy);
4574a33bea0SAnurag Kumar Vulisha }
4584a33bea0SAnurag Kumar Vulisha 
4594a33bea0SAnurag Kumar Vulisha /* Configure TX de-emphasis and margining for DP. */
4604a33bea0SAnurag Kumar Vulisha static void xpsgtr_phy_configure_dp(struct xpsgtr_phy *gtr_phy, unsigned int pre,
4614a33bea0SAnurag Kumar Vulisha 				    unsigned int voltage)
4624a33bea0SAnurag Kumar Vulisha {
4634a33bea0SAnurag Kumar Vulisha 	static const u8 voltage_swing[4][4] = {
4644a33bea0SAnurag Kumar Vulisha 		{ 0x2a, 0x27, 0x24, 0x20 },
4654a33bea0SAnurag Kumar Vulisha 		{ 0x27, 0x23, 0x20, 0xff },
4664a33bea0SAnurag Kumar Vulisha 		{ 0x24, 0x20, 0xff, 0xff },
4674a33bea0SAnurag Kumar Vulisha 		{ 0xff, 0xff, 0xff, 0xff }
4684a33bea0SAnurag Kumar Vulisha 	};
4694a33bea0SAnurag Kumar Vulisha 	static const u8 pre_emphasis[4][4] = {
4704a33bea0SAnurag Kumar Vulisha 		{ 0x02, 0x02, 0x02, 0x02 },
4714a33bea0SAnurag Kumar Vulisha 		{ 0x01, 0x01, 0x01, 0xff },
4724a33bea0SAnurag Kumar Vulisha 		{ 0x00, 0x00, 0xff, 0xff },
4734a33bea0SAnurag Kumar Vulisha 		{ 0xff, 0xff, 0xff, 0xff }
4744a33bea0SAnurag Kumar Vulisha 	};
4754a33bea0SAnurag Kumar Vulisha 
4764a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TXPMD_TM_48, voltage_swing[pre][voltage]);
4774a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TX_ANA_TM_18, pre_emphasis[pre][voltage]);
4784a33bea0SAnurag Kumar Vulisha }
4794a33bea0SAnurag Kumar Vulisha 
4804a33bea0SAnurag Kumar Vulisha /*
4814a33bea0SAnurag Kumar Vulisha  * PHY Operations
4824a33bea0SAnurag Kumar Vulisha  */
4834a33bea0SAnurag Kumar Vulisha 
4844a33bea0SAnurag Kumar Vulisha static bool xpsgtr_phy_init_required(struct xpsgtr_phy *gtr_phy)
4854a33bea0SAnurag Kumar Vulisha {
4864a33bea0SAnurag Kumar Vulisha 	/*
4874a33bea0SAnurag Kumar Vulisha 	 * As USB may save the snapshot of the states during hibernation, doing
4884a33bea0SAnurag Kumar Vulisha 	 * phy_init() will put the USB controller into reset, resulting in the
4894a33bea0SAnurag Kumar Vulisha 	 * losing of the saved snapshot. So try to avoid phy_init() for USB
4904a33bea0SAnurag Kumar Vulisha 	 * except when gtr_phy->skip_phy_init is false (this happens when FPD is
4914a33bea0SAnurag Kumar Vulisha 	 * shutdown during suspend or when gt lane is changed from current one)
4924a33bea0SAnurag Kumar Vulisha 	 */
4934a33bea0SAnurag Kumar Vulisha 	if (gtr_phy->protocol == ICM_PROTOCOL_USB && gtr_phy->skip_phy_init)
4944a33bea0SAnurag Kumar Vulisha 		return false;
4954a33bea0SAnurag Kumar Vulisha 	else
4964a33bea0SAnurag Kumar Vulisha 		return true;
4974a33bea0SAnurag Kumar Vulisha }
4984a33bea0SAnurag Kumar Vulisha 
4994a33bea0SAnurag Kumar Vulisha /*
5004a33bea0SAnurag Kumar Vulisha  * There is a functional issue in the GT. The TX termination resistance can be
5014a33bea0SAnurag Kumar Vulisha  * out of spec due to a issue in the calibration logic. This is the workaround
5024a33bea0SAnurag Kumar Vulisha  * to fix it, required for XCZU9EG silicon.
5034a33bea0SAnurag Kumar Vulisha  */
5044a33bea0SAnurag Kumar Vulisha static int xpsgtr_phy_tx_term_fix(struct xpsgtr_phy *gtr_phy)
5054a33bea0SAnurag Kumar Vulisha {
5064a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
5074a33bea0SAnurag Kumar Vulisha 	u32 timeout = TIMEOUT_US;
5084a33bea0SAnurag Kumar Vulisha 	u32 nsw;
5094a33bea0SAnurag Kumar Vulisha 
5104a33bea0SAnurag Kumar Vulisha 	/* Enabling Test Mode control for CMN Rest */
5114a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_dev, TM_CMN_RST, TM_CMN_RST_MASK, TM_CMN_RST_SET);
5124a33bea0SAnurag Kumar Vulisha 
5134a33bea0SAnurag Kumar Vulisha 	/* Set Test Mode reset */
5144a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_dev, TM_CMN_RST, TM_CMN_RST_MASK, TM_CMN_RST_EN);
5154a33bea0SAnurag Kumar Vulisha 
5164a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, L3_TM_CALIB_DIG18, 0x00);
5174a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, L3_TM_CALIB_DIG19, L3_TM_OVERRIDE_NSW_CODE);
5184a33bea0SAnurag Kumar Vulisha 
5194a33bea0SAnurag Kumar Vulisha 	/*
5204a33bea0SAnurag Kumar Vulisha 	 * As a part of work around sequence for PMOS calibration fix,
5214a33bea0SAnurag Kumar Vulisha 	 * we need to configure any lane ICM_CFG to valid protocol. This
5224a33bea0SAnurag Kumar Vulisha 	 * will deassert the CMN_Resetn signal.
5234a33bea0SAnurag Kumar Vulisha 	 */
5244a33bea0SAnurag Kumar Vulisha 	xpsgtr_lane_set_protocol(gtr_phy);
5254a33bea0SAnurag Kumar Vulisha 
5264a33bea0SAnurag Kumar Vulisha 	/* Clear Test Mode reset */
5274a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_dev, TM_CMN_RST, TM_CMN_RST_MASK, TM_CMN_RST_SET);
5284a33bea0SAnurag Kumar Vulisha 
5294a33bea0SAnurag Kumar Vulisha 	dev_dbg(gtr_dev->dev, "calibrating...\n");
5304a33bea0SAnurag Kumar Vulisha 
5314a33bea0SAnurag Kumar Vulisha 	do {
5324a33bea0SAnurag Kumar Vulisha 		u32 reg = xpsgtr_read(gtr_dev, L3_CALIB_DONE_STATUS);
5334a33bea0SAnurag Kumar Vulisha 
5344a33bea0SAnurag Kumar Vulisha 		if ((reg & L3_CALIB_DONE) == L3_CALIB_DONE)
5354a33bea0SAnurag Kumar Vulisha 			break;
5364a33bea0SAnurag Kumar Vulisha 
5374a33bea0SAnurag Kumar Vulisha 		if (!--timeout) {
5384a33bea0SAnurag Kumar Vulisha 			dev_err(gtr_dev->dev, "calibration time out\n");
5394a33bea0SAnurag Kumar Vulisha 			return -ETIMEDOUT;
5404a33bea0SAnurag Kumar Vulisha 		}
5414a33bea0SAnurag Kumar Vulisha 
5424a33bea0SAnurag Kumar Vulisha 		udelay(1);
5434a33bea0SAnurag Kumar Vulisha 	} while (timeout > 0);
5444a33bea0SAnurag Kumar Vulisha 
5454a33bea0SAnurag Kumar Vulisha 	dev_dbg(gtr_dev->dev, "calibration done\n");
5464a33bea0SAnurag Kumar Vulisha 
5474a33bea0SAnurag Kumar Vulisha 	/* Reading NMOS Register Code */
5484a33bea0SAnurag Kumar Vulisha 	nsw = xpsgtr_read(gtr_dev, L0_TXPMA_ST_3) & L0_DN_CALIB_CODE;
5494a33bea0SAnurag Kumar Vulisha 
5504a33bea0SAnurag Kumar Vulisha 	/* Set Test Mode reset */
5514a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_dev, TM_CMN_RST, TM_CMN_RST_MASK, TM_CMN_RST_EN);
5524a33bea0SAnurag Kumar Vulisha 
5534a33bea0SAnurag Kumar Vulisha 	/* Writing NMOS register values back [5:3] */
5544a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, L3_TM_CALIB_DIG19, nsw >> L3_NSW_CALIB_SHIFT);
5554a33bea0SAnurag Kumar Vulisha 
5564a33bea0SAnurag Kumar Vulisha 	/* Writing NMOS register value [2:0] */
5574a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, L3_TM_CALIB_DIG18,
5584a33bea0SAnurag Kumar Vulisha 		     ((nsw & L3_TM_CALIB_DIG19_NSW) << L3_NSW_SHIFT) |
5594a33bea0SAnurag Kumar Vulisha 		     (1 << L3_NSW_PIPE_SHIFT));
5604a33bea0SAnurag Kumar Vulisha 
5614a33bea0SAnurag Kumar Vulisha 	/* Clear Test Mode reset */
5624a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_dev, TM_CMN_RST, TM_CMN_RST_MASK, TM_CMN_RST_SET);
5634a33bea0SAnurag Kumar Vulisha 
5644a33bea0SAnurag Kumar Vulisha 	return 0;
5654a33bea0SAnurag Kumar Vulisha }
5664a33bea0SAnurag Kumar Vulisha 
5674a33bea0SAnurag Kumar Vulisha static int xpsgtr_phy_init(struct phy *phy)
5684a33bea0SAnurag Kumar Vulisha {
5694a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
5704a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
5714a33bea0SAnurag Kumar Vulisha 	int ret = 0;
5724a33bea0SAnurag Kumar Vulisha 
5734a33bea0SAnurag Kumar Vulisha 	mutex_lock(&gtr_dev->gtr_mutex);
5744a33bea0SAnurag Kumar Vulisha 
57525d70083SPiyush Mehta 	/* Configure and enable the clock when peripheral phy_init call */
57625d70083SPiyush Mehta 	if (clk_prepare_enable(gtr_dev->clk[gtr_phy->lane]))
57725d70083SPiyush Mehta 		goto out;
57825d70083SPiyush Mehta 
5794a33bea0SAnurag Kumar Vulisha 	/* Skip initialization if not required. */
5804a33bea0SAnurag Kumar Vulisha 	if (!xpsgtr_phy_init_required(gtr_phy))
5814a33bea0SAnurag Kumar Vulisha 		goto out;
5824a33bea0SAnurag Kumar Vulisha 
5834a33bea0SAnurag Kumar Vulisha 	if (gtr_dev->tx_term_fix) {
5844a33bea0SAnurag Kumar Vulisha 		ret = xpsgtr_phy_tx_term_fix(gtr_phy);
5854a33bea0SAnurag Kumar Vulisha 		if (ret < 0)
5864a33bea0SAnurag Kumar Vulisha 			goto out;
5874a33bea0SAnurag Kumar Vulisha 
5884a33bea0SAnurag Kumar Vulisha 		gtr_dev->tx_term_fix = false;
5894a33bea0SAnurag Kumar Vulisha 	}
5904a33bea0SAnurag Kumar Vulisha 
5914a33bea0SAnurag Kumar Vulisha 	/* Enable coarse code saturation limiting logic. */
5924a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TM_PLL_DIG_37, L0_TM_COARSE_CODE_LIMIT);
5934a33bea0SAnurag Kumar Vulisha 
5944a33bea0SAnurag Kumar Vulisha 	/*
5954a33bea0SAnurag Kumar Vulisha 	 * Configure the PLL, the lane protocol, and perform protocol-specific
5964a33bea0SAnurag Kumar Vulisha 	 * initialization.
5974a33bea0SAnurag Kumar Vulisha 	 */
5984a33bea0SAnurag Kumar Vulisha 	xpsgtr_configure_pll(gtr_phy);
5994a33bea0SAnurag Kumar Vulisha 	xpsgtr_lane_set_protocol(gtr_phy);
6004a33bea0SAnurag Kumar Vulisha 
6014a33bea0SAnurag Kumar Vulisha 	switch (gtr_phy->protocol) {
6024a33bea0SAnurag Kumar Vulisha 	case ICM_PROTOCOL_DP:
6034a33bea0SAnurag Kumar Vulisha 		xpsgtr_phy_init_dp(gtr_phy);
6044a33bea0SAnurag Kumar Vulisha 		break;
6054a33bea0SAnurag Kumar Vulisha 
6064a33bea0SAnurag Kumar Vulisha 	case ICM_PROTOCOL_SATA:
6074a33bea0SAnurag Kumar Vulisha 		xpsgtr_phy_init_sata(gtr_phy);
6084a33bea0SAnurag Kumar Vulisha 		break;
6094a33bea0SAnurag Kumar Vulisha 
6104a33bea0SAnurag Kumar Vulisha 	case ICM_PROTOCOL_SGMII:
6114a33bea0SAnurag Kumar Vulisha 		xpsgtr_phy_init_sgmii(gtr_phy);
6124a33bea0SAnurag Kumar Vulisha 		break;
6134a33bea0SAnurag Kumar Vulisha 	}
6144a33bea0SAnurag Kumar Vulisha 
6154a33bea0SAnurag Kumar Vulisha out:
6164a33bea0SAnurag Kumar Vulisha 	mutex_unlock(&gtr_dev->gtr_mutex);
6174a33bea0SAnurag Kumar Vulisha 	return ret;
6184a33bea0SAnurag Kumar Vulisha }
6194a33bea0SAnurag Kumar Vulisha 
6204a33bea0SAnurag Kumar Vulisha static int xpsgtr_phy_exit(struct phy *phy)
6214a33bea0SAnurag Kumar Vulisha {
6224a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
62325d70083SPiyush Mehta 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
6244a33bea0SAnurag Kumar Vulisha 
6254a33bea0SAnurag Kumar Vulisha 	gtr_phy->skip_phy_init = false;
6264a33bea0SAnurag Kumar Vulisha 
62725d70083SPiyush Mehta 	/* Ensure that disable clock only, which configure for lane */
62825d70083SPiyush Mehta 	clk_disable_unprepare(gtr_dev->clk[gtr_phy->lane]);
62925d70083SPiyush Mehta 
6304a33bea0SAnurag Kumar Vulisha 	return 0;
6314a33bea0SAnurag Kumar Vulisha }
6324a33bea0SAnurag Kumar Vulisha 
6334a33bea0SAnurag Kumar Vulisha static int xpsgtr_phy_power_on(struct phy *phy)
6344a33bea0SAnurag Kumar Vulisha {
6354a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
6364a33bea0SAnurag Kumar Vulisha 	int ret = 0;
6374a33bea0SAnurag Kumar Vulisha 
63889161cd0SPiyush Mehta 	/* Skip initialization if not required. */
63989161cd0SPiyush Mehta 	if (!xpsgtr_phy_init_required(gtr_phy))
64089161cd0SPiyush Mehta 		return ret;
6414a33bea0SAnurag Kumar Vulisha 	/*
6424a33bea0SAnurag Kumar Vulisha 	 * Wait for the PLL to lock. For DP, only wait on DP0 to avoid
6434a33bea0SAnurag Kumar Vulisha 	 * cumulating waits for both lanes. The user is expected to initialize
6444a33bea0SAnurag Kumar Vulisha 	 * lane 0 last.
6454a33bea0SAnurag Kumar Vulisha 	 */
6464a33bea0SAnurag Kumar Vulisha 	if (gtr_phy->protocol != ICM_PROTOCOL_DP ||
6474a33bea0SAnurag Kumar Vulisha 	    gtr_phy->type == XPSGTR_TYPE_DP_0)
6484a33bea0SAnurag Kumar Vulisha 		ret = xpsgtr_wait_pll_lock(phy);
6494a33bea0SAnurag Kumar Vulisha 
6504a33bea0SAnurag Kumar Vulisha 	return ret;
6514a33bea0SAnurag Kumar Vulisha }
6524a33bea0SAnurag Kumar Vulisha 
6534a33bea0SAnurag Kumar Vulisha static int xpsgtr_phy_configure(struct phy *phy, union phy_configure_opts *opts)
6544a33bea0SAnurag Kumar Vulisha {
6554a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
6564a33bea0SAnurag Kumar Vulisha 
6574a33bea0SAnurag Kumar Vulisha 	if (gtr_phy->protocol != ICM_PROTOCOL_DP)
6584a33bea0SAnurag Kumar Vulisha 		return 0;
6594a33bea0SAnurag Kumar Vulisha 
6604a33bea0SAnurag Kumar Vulisha 	xpsgtr_phy_configure_dp(gtr_phy, opts->dp.pre[0], opts->dp.voltage[0]);
6614a33bea0SAnurag Kumar Vulisha 
6624a33bea0SAnurag Kumar Vulisha 	return 0;
6634a33bea0SAnurag Kumar Vulisha }
6644a33bea0SAnurag Kumar Vulisha 
6654a33bea0SAnurag Kumar Vulisha static const struct phy_ops xpsgtr_phyops = {
6664a33bea0SAnurag Kumar Vulisha 	.init		= xpsgtr_phy_init,
6674a33bea0SAnurag Kumar Vulisha 	.exit		= xpsgtr_phy_exit,
6684a33bea0SAnurag Kumar Vulisha 	.power_on	= xpsgtr_phy_power_on,
6694a33bea0SAnurag Kumar Vulisha 	.configure	= xpsgtr_phy_configure,
6704a33bea0SAnurag Kumar Vulisha 	.owner		= THIS_MODULE,
6714a33bea0SAnurag Kumar Vulisha };
6724a33bea0SAnurag Kumar Vulisha 
6734a33bea0SAnurag Kumar Vulisha /*
6744a33bea0SAnurag Kumar Vulisha  * OF Xlate Support
6754a33bea0SAnurag Kumar Vulisha  */
6764a33bea0SAnurag Kumar Vulisha 
6774a33bea0SAnurag Kumar Vulisha /* Set the lane type and protocol based on the PHY type and instance number. */
6784a33bea0SAnurag Kumar Vulisha static int xpsgtr_set_lane_type(struct xpsgtr_phy *gtr_phy, u8 phy_type,
6794a33bea0SAnurag Kumar Vulisha 				unsigned int phy_instance)
6804a33bea0SAnurag Kumar Vulisha {
6814a33bea0SAnurag Kumar Vulisha 	unsigned int num_phy_types;
6824a33bea0SAnurag Kumar Vulisha 	const int *phy_types;
6834a33bea0SAnurag Kumar Vulisha 
6844a33bea0SAnurag Kumar Vulisha 	switch (phy_type) {
6854a33bea0SAnurag Kumar Vulisha 	case PHY_TYPE_SATA: {
6864a33bea0SAnurag Kumar Vulisha 		static const int types[] = {
6874a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_SATA_0,
6884a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_SATA_1,
6894a33bea0SAnurag Kumar Vulisha 		};
6904a33bea0SAnurag Kumar Vulisha 
6914a33bea0SAnurag Kumar Vulisha 		phy_types = types;
6924a33bea0SAnurag Kumar Vulisha 		num_phy_types = ARRAY_SIZE(types);
6934a33bea0SAnurag Kumar Vulisha 		gtr_phy->protocol = ICM_PROTOCOL_SATA;
6944a33bea0SAnurag Kumar Vulisha 		break;
6954a33bea0SAnurag Kumar Vulisha 	}
6964a33bea0SAnurag Kumar Vulisha 	case PHY_TYPE_USB3: {
6974a33bea0SAnurag Kumar Vulisha 		static const int types[] = {
6984a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_USB0,
6994a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_USB1,
7004a33bea0SAnurag Kumar Vulisha 		};
7014a33bea0SAnurag Kumar Vulisha 
7024a33bea0SAnurag Kumar Vulisha 		phy_types = types;
7034a33bea0SAnurag Kumar Vulisha 		num_phy_types = ARRAY_SIZE(types);
7044a33bea0SAnurag Kumar Vulisha 		gtr_phy->protocol = ICM_PROTOCOL_USB;
7054a33bea0SAnurag Kumar Vulisha 		break;
7064a33bea0SAnurag Kumar Vulisha 	}
7074a33bea0SAnurag Kumar Vulisha 	case PHY_TYPE_DP: {
7084a33bea0SAnurag Kumar Vulisha 		static const int types[] = {
7094a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_DP_0,
7104a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_DP_1,
7114a33bea0SAnurag Kumar Vulisha 		};
7124a33bea0SAnurag Kumar Vulisha 
7134a33bea0SAnurag Kumar Vulisha 		phy_types = types;
7144a33bea0SAnurag Kumar Vulisha 		num_phy_types = ARRAY_SIZE(types);
7154a33bea0SAnurag Kumar Vulisha 		gtr_phy->protocol = ICM_PROTOCOL_DP;
7164a33bea0SAnurag Kumar Vulisha 		break;
7174a33bea0SAnurag Kumar Vulisha 	}
7184a33bea0SAnurag Kumar Vulisha 	case PHY_TYPE_PCIE: {
7194a33bea0SAnurag Kumar Vulisha 		static const int types[] = {
7204a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_PCIE_0,
7214a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_PCIE_1,
7224a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_PCIE_2,
7234a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_PCIE_3,
7244a33bea0SAnurag Kumar Vulisha 		};
7254a33bea0SAnurag Kumar Vulisha 
7264a33bea0SAnurag Kumar Vulisha 		phy_types = types;
7274a33bea0SAnurag Kumar Vulisha 		num_phy_types = ARRAY_SIZE(types);
7284a33bea0SAnurag Kumar Vulisha 		gtr_phy->protocol = ICM_PROTOCOL_PCIE;
7294a33bea0SAnurag Kumar Vulisha 		break;
7304a33bea0SAnurag Kumar Vulisha 	}
7314a33bea0SAnurag Kumar Vulisha 	case PHY_TYPE_SGMII: {
7324a33bea0SAnurag Kumar Vulisha 		static const int types[] = {
7334a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_SGMII0,
7344a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_SGMII1,
7354a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_SGMII2,
7364a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_SGMII3,
7374a33bea0SAnurag Kumar Vulisha 		};
7384a33bea0SAnurag Kumar Vulisha 
7394a33bea0SAnurag Kumar Vulisha 		phy_types = types;
7404a33bea0SAnurag Kumar Vulisha 		num_phy_types = ARRAY_SIZE(types);
7414a33bea0SAnurag Kumar Vulisha 		gtr_phy->protocol = ICM_PROTOCOL_SGMII;
7424a33bea0SAnurag Kumar Vulisha 		break;
7434a33bea0SAnurag Kumar Vulisha 	}
7444a33bea0SAnurag Kumar Vulisha 	default:
7454a33bea0SAnurag Kumar Vulisha 		return -EINVAL;
7464a33bea0SAnurag Kumar Vulisha 	}
7474a33bea0SAnurag Kumar Vulisha 
7484a33bea0SAnurag Kumar Vulisha 	if (phy_instance >= num_phy_types)
7494a33bea0SAnurag Kumar Vulisha 		return -EINVAL;
7504a33bea0SAnurag Kumar Vulisha 
7514a33bea0SAnurag Kumar Vulisha 	gtr_phy->type = phy_types[phy_instance];
7524a33bea0SAnurag Kumar Vulisha 	return 0;
7534a33bea0SAnurag Kumar Vulisha }
7544a33bea0SAnurag Kumar Vulisha 
7554a33bea0SAnurag Kumar Vulisha /*
7564a33bea0SAnurag Kumar Vulisha  * Valid combinations of controllers and lanes (Interconnect Matrix).
7574a33bea0SAnurag Kumar Vulisha  */
7584a33bea0SAnurag Kumar Vulisha static const unsigned int icm_matrix[NUM_LANES][CONTROLLERS_PER_LANE] = {
7594a33bea0SAnurag Kumar Vulisha 	{ XPSGTR_TYPE_PCIE_0, XPSGTR_TYPE_SATA_0, XPSGTR_TYPE_USB0,
7604a33bea0SAnurag Kumar Vulisha 		XPSGTR_TYPE_DP_1, XPSGTR_TYPE_SGMII0 },
7614a33bea0SAnurag Kumar Vulisha 	{ XPSGTR_TYPE_PCIE_1, XPSGTR_TYPE_SATA_1, XPSGTR_TYPE_USB0,
7624a33bea0SAnurag Kumar Vulisha 		XPSGTR_TYPE_DP_0, XPSGTR_TYPE_SGMII1 },
7634a33bea0SAnurag Kumar Vulisha 	{ XPSGTR_TYPE_PCIE_2, XPSGTR_TYPE_SATA_0, XPSGTR_TYPE_USB0,
7644a33bea0SAnurag Kumar Vulisha 		XPSGTR_TYPE_DP_1, XPSGTR_TYPE_SGMII2 },
7654a33bea0SAnurag Kumar Vulisha 	{ XPSGTR_TYPE_PCIE_3, XPSGTR_TYPE_SATA_1, XPSGTR_TYPE_USB1,
7664a33bea0SAnurag Kumar Vulisha 		XPSGTR_TYPE_DP_0, XPSGTR_TYPE_SGMII3 }
7674a33bea0SAnurag Kumar Vulisha };
7684a33bea0SAnurag Kumar Vulisha 
7694a33bea0SAnurag Kumar Vulisha /* Translate OF phandle and args to PHY instance. */
7704a33bea0SAnurag Kumar Vulisha static struct phy *xpsgtr_xlate(struct device *dev,
77100ca8a15SKrzysztof Kozlowski 				const struct of_phandle_args *args)
7724a33bea0SAnurag Kumar Vulisha {
7734a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev);
7744a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy;
7754a33bea0SAnurag Kumar Vulisha 	unsigned int phy_instance;
7764a33bea0SAnurag Kumar Vulisha 	unsigned int phy_lane;
7774a33bea0SAnurag Kumar Vulisha 	unsigned int phy_type;
7784a33bea0SAnurag Kumar Vulisha 	unsigned int refclk;
7794a33bea0SAnurag Kumar Vulisha 	unsigned int i;
7804a33bea0SAnurag Kumar Vulisha 	int ret;
7814a33bea0SAnurag Kumar Vulisha 
7824a33bea0SAnurag Kumar Vulisha 	if (args->args_count != 4) {
7834a33bea0SAnurag Kumar Vulisha 		dev_err(dev, "Invalid number of cells in 'phy' property\n");
7844a33bea0SAnurag Kumar Vulisha 		return ERR_PTR(-EINVAL);
7854a33bea0SAnurag Kumar Vulisha 	}
7864a33bea0SAnurag Kumar Vulisha 
7874a33bea0SAnurag Kumar Vulisha 	/*
7884a33bea0SAnurag Kumar Vulisha 	 * Get the PHY parameters from the OF arguments and derive the lane
7894a33bea0SAnurag Kumar Vulisha 	 * type.
7904a33bea0SAnurag Kumar Vulisha 	 */
7914a33bea0SAnurag Kumar Vulisha 	phy_lane = args->args[0];
7924a33bea0SAnurag Kumar Vulisha 	if (phy_lane >= ARRAY_SIZE(gtr_dev->phys)) {
7934a33bea0SAnurag Kumar Vulisha 		dev_err(dev, "Invalid lane number %u\n", phy_lane);
7944a33bea0SAnurag Kumar Vulisha 		return ERR_PTR(-ENODEV);
7954a33bea0SAnurag Kumar Vulisha 	}
7964a33bea0SAnurag Kumar Vulisha 
7974a33bea0SAnurag Kumar Vulisha 	gtr_phy = &gtr_dev->phys[phy_lane];
7984a33bea0SAnurag Kumar Vulisha 	phy_type = args->args[1];
7994a33bea0SAnurag Kumar Vulisha 	phy_instance = args->args[2];
8004a33bea0SAnurag Kumar Vulisha 
8014a33bea0SAnurag Kumar Vulisha 	ret = xpsgtr_set_lane_type(gtr_phy, phy_type, phy_instance);
8024a33bea0SAnurag Kumar Vulisha 	if (ret < 0) {
8034a33bea0SAnurag Kumar Vulisha 		dev_err(gtr_dev->dev, "Invalid PHY type and/or instance\n");
8044a33bea0SAnurag Kumar Vulisha 		return ERR_PTR(ret);
8054a33bea0SAnurag Kumar Vulisha 	}
8064a33bea0SAnurag Kumar Vulisha 
8074a33bea0SAnurag Kumar Vulisha 	refclk = args->args[3];
8084a33bea0SAnurag Kumar Vulisha 	if (refclk >= ARRAY_SIZE(gtr_dev->refclk_sscs) ||
8094a33bea0SAnurag Kumar Vulisha 	    !gtr_dev->refclk_sscs[refclk]) {
8104a33bea0SAnurag Kumar Vulisha 		dev_err(dev, "Invalid reference clock number %u\n", refclk);
8114a33bea0SAnurag Kumar Vulisha 		return ERR_PTR(-EINVAL);
8124a33bea0SAnurag Kumar Vulisha 	}
8134a33bea0SAnurag Kumar Vulisha 
8144a33bea0SAnurag Kumar Vulisha 	gtr_phy->refclk = refclk;
8154a33bea0SAnurag Kumar Vulisha 
8164a33bea0SAnurag Kumar Vulisha 	/*
8174a33bea0SAnurag Kumar Vulisha 	 * Ensure that the Interconnect Matrix is obeyed, i.e a given lane type
8184a33bea0SAnurag Kumar Vulisha 	 * is allowed to operate on the lane.
8194a33bea0SAnurag Kumar Vulisha 	 */
8204a33bea0SAnurag Kumar Vulisha 	for (i = 0; i < CONTROLLERS_PER_LANE; i++) {
8214a33bea0SAnurag Kumar Vulisha 		if (icm_matrix[phy_lane][i] == gtr_phy->type)
8224a33bea0SAnurag Kumar Vulisha 			return gtr_phy->phy;
8234a33bea0SAnurag Kumar Vulisha 	}
8244a33bea0SAnurag Kumar Vulisha 
8254a33bea0SAnurag Kumar Vulisha 	return ERR_PTR(-EINVAL);
8264a33bea0SAnurag Kumar Vulisha }
8274a33bea0SAnurag Kumar Vulisha 
8284a33bea0SAnurag Kumar Vulisha /*
8294a33bea0SAnurag Kumar Vulisha  * Power Management
8304a33bea0SAnurag Kumar Vulisha  */
8314a33bea0SAnurag Kumar Vulisha 
832b3db66f6SPiyush Mehta static int xpsgtr_runtime_suspend(struct device *dev)
8334a33bea0SAnurag Kumar Vulisha {
8344a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev);
8354a33bea0SAnurag Kumar Vulisha 
8364a33bea0SAnurag Kumar Vulisha 	/* Save the snapshot ICM_CFG registers. */
8374a33bea0SAnurag Kumar Vulisha 	gtr_dev->saved_icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0);
8384a33bea0SAnurag Kumar Vulisha 	gtr_dev->saved_icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1);
8394a33bea0SAnurag Kumar Vulisha 
8404a33bea0SAnurag Kumar Vulisha 	return 0;
8414a33bea0SAnurag Kumar Vulisha }
8424a33bea0SAnurag Kumar Vulisha 
843b3db66f6SPiyush Mehta static int xpsgtr_runtime_resume(struct device *dev)
8444a33bea0SAnurag Kumar Vulisha {
8454a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev);
8464a33bea0SAnurag Kumar Vulisha 	unsigned int icm_cfg0, icm_cfg1;
8474a33bea0SAnurag Kumar Vulisha 	unsigned int i;
8484a33bea0SAnurag Kumar Vulisha 	bool skip_phy_init;
8494a33bea0SAnurag Kumar Vulisha 
8504a33bea0SAnurag Kumar Vulisha 	icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0);
8514a33bea0SAnurag Kumar Vulisha 	icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1);
8524a33bea0SAnurag Kumar Vulisha 
8534a33bea0SAnurag Kumar Vulisha 	/* Return if no GT lanes got configured before suspend. */
8544a33bea0SAnurag Kumar Vulisha 	if (!gtr_dev->saved_icm_cfg0 && !gtr_dev->saved_icm_cfg1)
8554a33bea0SAnurag Kumar Vulisha 		return 0;
8564a33bea0SAnurag Kumar Vulisha 
8574a33bea0SAnurag Kumar Vulisha 	/* Check if the ICM configurations changed after suspend. */
8584a33bea0SAnurag Kumar Vulisha 	if (icm_cfg0 == gtr_dev->saved_icm_cfg0 &&
8594a33bea0SAnurag Kumar Vulisha 	    icm_cfg1 == gtr_dev->saved_icm_cfg1)
8604a33bea0SAnurag Kumar Vulisha 		skip_phy_init = true;
8614a33bea0SAnurag Kumar Vulisha 	else
8624a33bea0SAnurag Kumar Vulisha 		skip_phy_init = false;
8634a33bea0SAnurag Kumar Vulisha 
8644a33bea0SAnurag Kumar Vulisha 	/* Update the skip_phy_init for all gtr_phy instances. */
8654a33bea0SAnurag Kumar Vulisha 	for (i = 0; i < ARRAY_SIZE(gtr_dev->phys); i++)
8664a33bea0SAnurag Kumar Vulisha 		gtr_dev->phys[i].skip_phy_init = skip_phy_init;
8674a33bea0SAnurag Kumar Vulisha 
8684a33bea0SAnurag Kumar Vulisha 	return 0;
8694a33bea0SAnurag Kumar Vulisha }
8704a33bea0SAnurag Kumar Vulisha 
871b3db66f6SPiyush Mehta static DEFINE_RUNTIME_DEV_PM_OPS(xpsgtr_pm_ops, xpsgtr_runtime_suspend,
872b3db66f6SPiyush Mehta 				 xpsgtr_runtime_resume, NULL);
8734a33bea0SAnurag Kumar Vulisha /*
8744a33bea0SAnurag Kumar Vulisha  * Probe & Platform Driver
8754a33bea0SAnurag Kumar Vulisha  */
8764a33bea0SAnurag Kumar Vulisha 
8774a33bea0SAnurag Kumar Vulisha static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev)
8784a33bea0SAnurag Kumar Vulisha {
8794a33bea0SAnurag Kumar Vulisha 	unsigned int refclk;
8804a33bea0SAnurag Kumar Vulisha 
8814a33bea0SAnurag Kumar Vulisha 	for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->refclk_sscs); ++refclk) {
8824a33bea0SAnurag Kumar Vulisha 		unsigned long rate;
8834a33bea0SAnurag Kumar Vulisha 		unsigned int i;
8844a33bea0SAnurag Kumar Vulisha 		struct clk *clk;
8854a33bea0SAnurag Kumar Vulisha 		char name[8];
8864a33bea0SAnurag Kumar Vulisha 
8874a33bea0SAnurag Kumar Vulisha 		snprintf(name, sizeof(name), "ref%u", refclk);
8884a33bea0SAnurag Kumar Vulisha 		clk = devm_clk_get_optional(gtr_dev->dev, name);
88967097754SManish Narani 		if (IS_ERR(clk)) {
89025d70083SPiyush Mehta 			return dev_err_probe(gtr_dev->dev, PTR_ERR(clk),
89125d70083SPiyush Mehta 					     "Failed to get ref clock %u\n",
8923dbbc8e9SMichal Simek 					     refclk);
89367097754SManish Narani 		}
8944a33bea0SAnurag Kumar Vulisha 
8954a33bea0SAnurag Kumar Vulisha 		if (!clk)
8964a33bea0SAnurag Kumar Vulisha 			continue;
8974a33bea0SAnurag Kumar Vulisha 
89867097754SManish Narani 		gtr_dev->clk[refclk] = clk;
89967097754SManish Narani 
9004a33bea0SAnurag Kumar Vulisha 		/*
9014a33bea0SAnurag Kumar Vulisha 		 * Get the spread spectrum (SSC) settings for the reference
9024a33bea0SAnurag Kumar Vulisha 		 * clock rate.
9034a33bea0SAnurag Kumar Vulisha 		 */
9044a33bea0SAnurag Kumar Vulisha 		rate = clk_get_rate(clk);
9054a33bea0SAnurag Kumar Vulisha 
9064a33bea0SAnurag Kumar Vulisha 		for (i = 0 ; i < ARRAY_SIZE(ssc_lookup); i++) {
90776009ee7SSean Anderson 			/* Allow an error of 100 ppm */
90876009ee7SSean Anderson 			unsigned long error = ssc_lookup[i].refclk_rate / 10000;
90976009ee7SSean Anderson 
91076009ee7SSean Anderson 			if (abs(rate - ssc_lookup[i].refclk_rate) < error) {
9114a33bea0SAnurag Kumar Vulisha 				gtr_dev->refclk_sscs[refclk] = &ssc_lookup[i];
9124a33bea0SAnurag Kumar Vulisha 				break;
9134a33bea0SAnurag Kumar Vulisha 			}
9144a33bea0SAnurag Kumar Vulisha 		}
9154a33bea0SAnurag Kumar Vulisha 
9164a33bea0SAnurag Kumar Vulisha 		if (i == ARRAY_SIZE(ssc_lookup)) {
9174a33bea0SAnurag Kumar Vulisha 			dev_err(gtr_dev->dev,
9184a33bea0SAnurag Kumar Vulisha 				"Invalid rate %lu for reference clock %u\n",
9194a33bea0SAnurag Kumar Vulisha 				rate, refclk);
92025d70083SPiyush Mehta 			return -EINVAL;
9214a33bea0SAnurag Kumar Vulisha 		}
9224a33bea0SAnurag Kumar Vulisha 	}
9234a33bea0SAnurag Kumar Vulisha 
9244a33bea0SAnurag Kumar Vulisha 	return 0;
9254a33bea0SAnurag Kumar Vulisha }
9264a33bea0SAnurag Kumar Vulisha 
9274a33bea0SAnurag Kumar Vulisha static int xpsgtr_probe(struct platform_device *pdev)
9284a33bea0SAnurag Kumar Vulisha {
9294a33bea0SAnurag Kumar Vulisha 	struct device_node *np = pdev->dev.of_node;
9304a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev;
9314a33bea0SAnurag Kumar Vulisha 	struct phy_provider *provider;
9324a33bea0SAnurag Kumar Vulisha 	unsigned int port;
9334a33bea0SAnurag Kumar Vulisha 	int ret;
9344a33bea0SAnurag Kumar Vulisha 
9354a33bea0SAnurag Kumar Vulisha 	gtr_dev = devm_kzalloc(&pdev->dev, sizeof(*gtr_dev), GFP_KERNEL);
9364a33bea0SAnurag Kumar Vulisha 	if (!gtr_dev)
9374a33bea0SAnurag Kumar Vulisha 		return -ENOMEM;
9384a33bea0SAnurag Kumar Vulisha 
9394a33bea0SAnurag Kumar Vulisha 	gtr_dev->dev = &pdev->dev;
9404a33bea0SAnurag Kumar Vulisha 	platform_set_drvdata(pdev, gtr_dev);
9414a33bea0SAnurag Kumar Vulisha 
9424a33bea0SAnurag Kumar Vulisha 	mutex_init(&gtr_dev->gtr_mutex);
9434a33bea0SAnurag Kumar Vulisha 
9444a33bea0SAnurag Kumar Vulisha 	if (of_device_is_compatible(np, "xlnx,zynqmp-psgtr"))
9454a33bea0SAnurag Kumar Vulisha 		gtr_dev->tx_term_fix =
9464a33bea0SAnurag Kumar Vulisha 			of_property_read_bool(np, "xlnx,tx-termination-fix");
9474a33bea0SAnurag Kumar Vulisha 
9484a33bea0SAnurag Kumar Vulisha 	/* Acquire resources. */
9494a33bea0SAnurag Kumar Vulisha 	gtr_dev->serdes = devm_platform_ioremap_resource_byname(pdev, "serdes");
9504a33bea0SAnurag Kumar Vulisha 	if (IS_ERR(gtr_dev->serdes))
9514a33bea0SAnurag Kumar Vulisha 		return PTR_ERR(gtr_dev->serdes);
9524a33bea0SAnurag Kumar Vulisha 
9534a33bea0SAnurag Kumar Vulisha 	gtr_dev->siou = devm_platform_ioremap_resource_byname(pdev, "siou");
9544a33bea0SAnurag Kumar Vulisha 	if (IS_ERR(gtr_dev->siou))
9554a33bea0SAnurag Kumar Vulisha 		return PTR_ERR(gtr_dev->siou);
9564a33bea0SAnurag Kumar Vulisha 
9574a33bea0SAnurag Kumar Vulisha 	ret = xpsgtr_get_ref_clocks(gtr_dev);
9584a33bea0SAnurag Kumar Vulisha 	if (ret)
9594a33bea0SAnurag Kumar Vulisha 		return ret;
9604a33bea0SAnurag Kumar Vulisha 
9614a33bea0SAnurag Kumar Vulisha 	/* Create PHYs. */
9624a33bea0SAnurag Kumar Vulisha 	for (port = 0; port < ARRAY_SIZE(gtr_dev->phys); ++port) {
9634a33bea0SAnurag Kumar Vulisha 		struct xpsgtr_phy *gtr_phy = &gtr_dev->phys[port];
9644a33bea0SAnurag Kumar Vulisha 		struct phy *phy;
9654a33bea0SAnurag Kumar Vulisha 
9664a33bea0SAnurag Kumar Vulisha 		gtr_phy->lane = port;
9674a33bea0SAnurag Kumar Vulisha 		gtr_phy->dev = gtr_dev;
9684a33bea0SAnurag Kumar Vulisha 
9694a33bea0SAnurag Kumar Vulisha 		phy = devm_phy_create(&pdev->dev, np, &xpsgtr_phyops);
9704a33bea0SAnurag Kumar Vulisha 		if (IS_ERR(phy)) {
9714a33bea0SAnurag Kumar Vulisha 			dev_err(&pdev->dev, "failed to create PHY\n");
97225d70083SPiyush Mehta 			return PTR_ERR(phy);
9734a33bea0SAnurag Kumar Vulisha 		}
9744a33bea0SAnurag Kumar Vulisha 
9754a33bea0SAnurag Kumar Vulisha 		gtr_phy->phy = phy;
9764a33bea0SAnurag Kumar Vulisha 		phy_set_drvdata(phy, gtr_phy);
9774a33bea0SAnurag Kumar Vulisha 	}
9784a33bea0SAnurag Kumar Vulisha 
9794a33bea0SAnurag Kumar Vulisha 	/* Register the PHY provider. */
9804a33bea0SAnurag Kumar Vulisha 	provider = devm_of_phy_provider_register(&pdev->dev, xpsgtr_xlate);
9814a33bea0SAnurag Kumar Vulisha 	if (IS_ERR(provider)) {
9824a33bea0SAnurag Kumar Vulisha 		dev_err(&pdev->dev, "registering provider failed\n");
98325d70083SPiyush Mehta 		return PTR_ERR(provider);
9844a33bea0SAnurag Kumar Vulisha 	}
985b3db66f6SPiyush Mehta 
986b3db66f6SPiyush Mehta 	pm_runtime_set_active(gtr_dev->dev);
987b3db66f6SPiyush Mehta 	pm_runtime_enable(gtr_dev->dev);
988b3db66f6SPiyush Mehta 
989b3db66f6SPiyush Mehta 	ret = pm_runtime_resume_and_get(gtr_dev->dev);
990b3db66f6SPiyush Mehta 	if (ret < 0) {
991b3db66f6SPiyush Mehta 		pm_runtime_disable(gtr_dev->dev);
99225d70083SPiyush Mehta 		return ret;
993b3db66f6SPiyush Mehta 	}
994b3db66f6SPiyush Mehta 
9954a33bea0SAnurag Kumar Vulisha 	return 0;
9964a33bea0SAnurag Kumar Vulisha }
9974a33bea0SAnurag Kumar Vulisha 
998*7dcb8668SUwe Kleine-König static void xpsgtr_remove(struct platform_device *pdev)
999b3db66f6SPiyush Mehta {
1000b3db66f6SPiyush Mehta 	struct xpsgtr_dev *gtr_dev = platform_get_drvdata(pdev);
1001b3db66f6SPiyush Mehta 
1002b3db66f6SPiyush Mehta 	pm_runtime_disable(gtr_dev->dev);
1003b3db66f6SPiyush Mehta 	pm_runtime_put_noidle(gtr_dev->dev);
1004b3db66f6SPiyush Mehta 	pm_runtime_set_suspended(gtr_dev->dev);
1005b3db66f6SPiyush Mehta }
1006b3db66f6SPiyush Mehta 
10074a33bea0SAnurag Kumar Vulisha static const struct of_device_id xpsgtr_of_match[] = {
10084a33bea0SAnurag Kumar Vulisha 	{ .compatible = "xlnx,zynqmp-psgtr", },
10094a33bea0SAnurag Kumar Vulisha 	{ .compatible = "xlnx,zynqmp-psgtr-v1.1", },
10104a33bea0SAnurag Kumar Vulisha 	{},
10114a33bea0SAnurag Kumar Vulisha };
10124a33bea0SAnurag Kumar Vulisha MODULE_DEVICE_TABLE(of, xpsgtr_of_match);
10134a33bea0SAnurag Kumar Vulisha 
10144a33bea0SAnurag Kumar Vulisha static struct platform_driver xpsgtr_driver = {
10154a33bea0SAnurag Kumar Vulisha 	.probe = xpsgtr_probe,
1016*7dcb8668SUwe Kleine-König 	.remove_new = xpsgtr_remove,
10174a33bea0SAnurag Kumar Vulisha 	.driver = {
10184a33bea0SAnurag Kumar Vulisha 		.name = "xilinx-psgtr",
10194a33bea0SAnurag Kumar Vulisha 		.of_match_table	= xpsgtr_of_match,
1020b3db66f6SPiyush Mehta 		.pm =  pm_ptr(&xpsgtr_pm_ops),
10214a33bea0SAnurag Kumar Vulisha 	},
10224a33bea0SAnurag Kumar Vulisha };
10234a33bea0SAnurag Kumar Vulisha 
10244a33bea0SAnurag Kumar Vulisha module_platform_driver(xpsgtr_driver);
10254a33bea0SAnurag Kumar Vulisha 
10264a33bea0SAnurag Kumar Vulisha MODULE_AUTHOR("Xilinx Inc.");
10274a33bea0SAnurag Kumar Vulisha MODULE_LICENSE("GPL v2");
10284a33bea0SAnurag Kumar Vulisha MODULE_DESCRIPTION("Xilinx ZynqMP High speed Gigabit Transceiver");
1029