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