xref: /linux/drivers/phy/xilinx/phy-zynqmp.c (revision 4a33bea003144e217d8a3ae666f171dfc2e97bd6)
1*4a33bea0SAnurag Kumar Vulisha // SPDX-License-Identifier: GPL-2.0
2*4a33bea0SAnurag Kumar Vulisha /*
3*4a33bea0SAnurag Kumar Vulisha  * phy-zynqmp.c - PHY driver for Xilinx ZynqMP GT.
4*4a33bea0SAnurag Kumar Vulisha  *
5*4a33bea0SAnurag Kumar Vulisha  * Copyright (C) 2018-2020 Xilinx Inc.
6*4a33bea0SAnurag Kumar Vulisha  *
7*4a33bea0SAnurag Kumar Vulisha  * Author: Anurag Kumar Vulisha <anuragku@xilinx.com>
8*4a33bea0SAnurag Kumar Vulisha  * Author: Subbaraya Sundeep <sundeep.lkml@gmail.com>
9*4a33bea0SAnurag Kumar Vulisha  * Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
10*4a33bea0SAnurag Kumar Vulisha  *
11*4a33bea0SAnurag Kumar Vulisha  * This driver is tested for USB, SATA and Display Port currently.
12*4a33bea0SAnurag Kumar Vulisha  * Other controllers PCIe and SGMII should also work but that is
13*4a33bea0SAnurag Kumar Vulisha  * experimental as of now.
14*4a33bea0SAnurag Kumar Vulisha  */
15*4a33bea0SAnurag Kumar Vulisha 
16*4a33bea0SAnurag Kumar Vulisha #include <linux/clk.h>
17*4a33bea0SAnurag Kumar Vulisha #include <linux/delay.h>
18*4a33bea0SAnurag Kumar Vulisha #include <linux/io.h>
19*4a33bea0SAnurag Kumar Vulisha #include <linux/kernel.h>
20*4a33bea0SAnurag Kumar Vulisha #include <linux/module.h>
21*4a33bea0SAnurag Kumar Vulisha #include <linux/of.h>
22*4a33bea0SAnurag Kumar Vulisha #include <linux/phy/phy.h>
23*4a33bea0SAnurag Kumar Vulisha #include <linux/platform_device.h>
24*4a33bea0SAnurag Kumar Vulisha #include <linux/slab.h>
25*4a33bea0SAnurag Kumar Vulisha 
26*4a33bea0SAnurag Kumar Vulisha #include <dt-bindings/phy/phy.h>
27*4a33bea0SAnurag Kumar Vulisha 
28*4a33bea0SAnurag Kumar Vulisha /*
29*4a33bea0SAnurag Kumar Vulisha  * Lane Registers
30*4a33bea0SAnurag Kumar Vulisha  */
31*4a33bea0SAnurag Kumar Vulisha 
32*4a33bea0SAnurag Kumar Vulisha /* TX De-emphasis parameters */
33*4a33bea0SAnurag Kumar Vulisha #define L0_TX_ANA_TM_18			0x0048
34*4a33bea0SAnurag Kumar Vulisha #define L0_TX_ANA_TM_118		0x01d8
35*4a33bea0SAnurag Kumar Vulisha #define L0_TX_ANA_TM_118_FORCE_17_0	BIT(0)
36*4a33bea0SAnurag Kumar Vulisha 
37*4a33bea0SAnurag Kumar Vulisha /* DN Resistor calibration code parameters */
38*4a33bea0SAnurag Kumar Vulisha #define L0_TXPMA_ST_3			0x0b0c
39*4a33bea0SAnurag Kumar Vulisha #define L0_DN_CALIB_CODE		0x3f
40*4a33bea0SAnurag Kumar Vulisha 
41*4a33bea0SAnurag Kumar Vulisha /* PMA control parameters */
42*4a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45			0x0cb4
43*4a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_48			0x0cc0
44*4a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_OVER_DP_MAIN	BIT(0)
45*4a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_ENABLE_DP_MAIN	BIT(1)
46*4a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_OVER_DP_POST1	BIT(2)
47*4a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_ENABLE_DP_POST1	BIT(3)
48*4a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_OVER_DP_POST2	BIT(4)
49*4a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_ENABLE_DP_POST2	BIT(5)
50*4a33bea0SAnurag Kumar Vulisha 
51*4a33bea0SAnurag Kumar Vulisha /* PCS control parameters */
52*4a33bea0SAnurag Kumar Vulisha #define L0_TM_DIG_6			0x106c
53*4a33bea0SAnurag Kumar Vulisha #define L0_TM_DIS_DESCRAMBLE_DECODER	0x0f
54*4a33bea0SAnurag Kumar Vulisha #define L0_TX_DIG_61			0x00f4
55*4a33bea0SAnurag Kumar Vulisha #define L0_TM_DISABLE_SCRAMBLE_ENCODER	0x0f
56*4a33bea0SAnurag Kumar Vulisha 
57*4a33bea0SAnurag Kumar Vulisha /* PLL Test Mode register parameters */
58*4a33bea0SAnurag Kumar Vulisha #define L0_TM_PLL_DIG_37		0x2094
59*4a33bea0SAnurag Kumar Vulisha #define L0_TM_COARSE_CODE_LIMIT		0x10
60*4a33bea0SAnurag Kumar Vulisha 
61*4a33bea0SAnurag Kumar Vulisha /* PLL SSC step size offsets */
62*4a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEPS_0_LSB		0x2368
63*4a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEPS_1_MSB		0x236c
64*4a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEP_SIZE_0_LSB	0x2370
65*4a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEP_SIZE_1		0x2374
66*4a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEP_SIZE_2		0x2378
67*4a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEP_SIZE_3_MSB	0x237c
68*4a33bea0SAnurag Kumar Vulisha #define L0_PLL_STATUS_READ_1		0x23e4
69*4a33bea0SAnurag Kumar Vulisha 
70*4a33bea0SAnurag Kumar Vulisha /* SSC step size parameters */
71*4a33bea0SAnurag Kumar Vulisha #define STEP_SIZE_0_MASK		0xff
72*4a33bea0SAnurag Kumar Vulisha #define STEP_SIZE_1_MASK		0xff
73*4a33bea0SAnurag Kumar Vulisha #define STEP_SIZE_2_MASK		0xff
74*4a33bea0SAnurag Kumar Vulisha #define STEP_SIZE_3_MASK		0x3
75*4a33bea0SAnurag Kumar Vulisha #define STEP_SIZE_SHIFT			8
76*4a33bea0SAnurag Kumar Vulisha #define FORCE_STEP_SIZE			0x10
77*4a33bea0SAnurag Kumar Vulisha #define FORCE_STEPS			0x20
78*4a33bea0SAnurag Kumar Vulisha #define STEPS_0_MASK			0xff
79*4a33bea0SAnurag Kumar Vulisha #define STEPS_1_MASK			0x07
80*4a33bea0SAnurag Kumar Vulisha 
81*4a33bea0SAnurag Kumar Vulisha /* Reference clock selection parameters */
82*4a33bea0SAnurag Kumar Vulisha #define L0_Ln_REF_CLK_SEL(n)		(0x2860 + (n) * 4)
83*4a33bea0SAnurag Kumar Vulisha #define L0_REF_CLK_SEL_MASK		0x8f
84*4a33bea0SAnurag Kumar Vulisha 
85*4a33bea0SAnurag Kumar Vulisha /* Calibration digital logic parameters */
86*4a33bea0SAnurag Kumar Vulisha #define L3_TM_CALIB_DIG19		0xec4c
87*4a33bea0SAnurag Kumar Vulisha #define L3_CALIB_DONE_STATUS		0xef14
88*4a33bea0SAnurag Kumar Vulisha #define L3_TM_CALIB_DIG18		0xec48
89*4a33bea0SAnurag Kumar Vulisha #define L3_TM_CALIB_DIG19_NSW		0x07
90*4a33bea0SAnurag Kumar Vulisha #define L3_TM_CALIB_DIG18_NSW		0xe0
91*4a33bea0SAnurag Kumar Vulisha #define L3_TM_OVERRIDE_NSW_CODE         0x20
92*4a33bea0SAnurag Kumar Vulisha #define L3_CALIB_DONE			0x02
93*4a33bea0SAnurag Kumar Vulisha #define L3_NSW_SHIFT			5
94*4a33bea0SAnurag Kumar Vulisha #define L3_NSW_PIPE_SHIFT		4
95*4a33bea0SAnurag Kumar Vulisha #define L3_NSW_CALIB_SHIFT		3
96*4a33bea0SAnurag Kumar Vulisha 
97*4a33bea0SAnurag Kumar Vulisha #define PHY_REG_OFFSET			0x4000
98*4a33bea0SAnurag Kumar Vulisha 
99*4a33bea0SAnurag Kumar Vulisha /*
100*4a33bea0SAnurag Kumar Vulisha  * Global Registers
101*4a33bea0SAnurag Kumar Vulisha  */
102*4a33bea0SAnurag Kumar Vulisha 
103*4a33bea0SAnurag Kumar Vulisha /* Refclk selection parameters */
104*4a33bea0SAnurag Kumar Vulisha #define PLL_REF_SEL(n)			(0x10000 + (n) * 4)
105*4a33bea0SAnurag Kumar Vulisha #define PLL_FREQ_MASK			0x1f
106*4a33bea0SAnurag Kumar Vulisha #define PLL_STATUS_LOCKED		0x10
107*4a33bea0SAnurag Kumar Vulisha 
108*4a33bea0SAnurag Kumar Vulisha /* Inter Connect Matrix parameters */
109*4a33bea0SAnurag Kumar Vulisha #define ICM_CFG0			0x10010
110*4a33bea0SAnurag Kumar Vulisha #define ICM_CFG1			0x10014
111*4a33bea0SAnurag Kumar Vulisha #define ICM_CFG0_L0_MASK		0x07
112*4a33bea0SAnurag Kumar Vulisha #define ICM_CFG0_L1_MASK		0x70
113*4a33bea0SAnurag Kumar Vulisha #define ICM_CFG1_L2_MASK		0x07
114*4a33bea0SAnurag Kumar Vulisha #define ICM_CFG2_L3_MASK		0x70
115*4a33bea0SAnurag Kumar Vulisha #define ICM_CFG_SHIFT			4
116*4a33bea0SAnurag Kumar Vulisha 
117*4a33bea0SAnurag Kumar Vulisha /* Inter Connect Matrix allowed protocols */
118*4a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_PD			0x0
119*4a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_PCIE		0x1
120*4a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_SATA		0x2
121*4a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_USB		0x3
122*4a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_DP			0x4
123*4a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_SGMII		0x5
124*4a33bea0SAnurag Kumar Vulisha 
125*4a33bea0SAnurag Kumar Vulisha /* Test Mode common reset control  parameters */
126*4a33bea0SAnurag Kumar Vulisha #define TM_CMN_RST			0x10018
127*4a33bea0SAnurag Kumar Vulisha #define TM_CMN_RST_EN			0x1
128*4a33bea0SAnurag Kumar Vulisha #define TM_CMN_RST_SET			0x2
129*4a33bea0SAnurag Kumar Vulisha #define TM_CMN_RST_MASK			0x3
130*4a33bea0SAnurag Kumar Vulisha 
131*4a33bea0SAnurag Kumar Vulisha /* Bus width parameters */
132*4a33bea0SAnurag Kumar Vulisha #define TX_PROT_BUS_WIDTH		0x10040
133*4a33bea0SAnurag Kumar Vulisha #define RX_PROT_BUS_WIDTH		0x10044
134*4a33bea0SAnurag Kumar Vulisha #define PROT_BUS_WIDTH_10		0x0
135*4a33bea0SAnurag Kumar Vulisha #define PROT_BUS_WIDTH_20		0x1
136*4a33bea0SAnurag Kumar Vulisha #define PROT_BUS_WIDTH_40		0x2
137*4a33bea0SAnurag Kumar Vulisha #define PROT_BUS_WIDTH_SHIFT		2
138*4a33bea0SAnurag Kumar Vulisha 
139*4a33bea0SAnurag Kumar Vulisha /* Number of GT lanes */
140*4a33bea0SAnurag Kumar Vulisha #define NUM_LANES			4
141*4a33bea0SAnurag Kumar Vulisha 
142*4a33bea0SAnurag Kumar Vulisha /* SIOU SATA control register */
143*4a33bea0SAnurag Kumar Vulisha #define SATA_CONTROL_OFFSET		0x0100
144*4a33bea0SAnurag Kumar Vulisha 
145*4a33bea0SAnurag Kumar Vulisha /* Total number of controllers */
146*4a33bea0SAnurag Kumar Vulisha #define CONTROLLERS_PER_LANE		5
147*4a33bea0SAnurag Kumar Vulisha 
148*4a33bea0SAnurag Kumar Vulisha /* Protocol Type parameters */
149*4a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_USB0		0  /* USB controller 0 */
150*4a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_USB1		1  /* USB controller 1 */
151*4a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_SATA_0		2  /* SATA controller lane 0 */
152*4a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_SATA_1		3  /* SATA controller lane 1 */
153*4a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_PCIE_0		4  /* PCIe controller lane 0 */
154*4a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_PCIE_1		5  /* PCIe controller lane 1 */
155*4a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_PCIE_2		6  /* PCIe controller lane 2 */
156*4a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_PCIE_3		7  /* PCIe controller lane 3 */
157*4a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_DP_0		8  /* Display Port controller lane 0 */
158*4a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_DP_1		9  /* Display Port controller lane 1 */
159*4a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_SGMII0		10 /* Ethernet SGMII controller 0 */
160*4a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_SGMII1		11 /* Ethernet SGMII controller 1 */
161*4a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_SGMII2		12 /* Ethernet SGMII controller 2 */
162*4a33bea0SAnurag Kumar Vulisha #define XPSGTR_TYPE_SGMII3		13 /* Ethernet SGMII controller 3 */
163*4a33bea0SAnurag Kumar Vulisha 
164*4a33bea0SAnurag Kumar Vulisha /* Timeout values */
165*4a33bea0SAnurag Kumar Vulisha #define TIMEOUT_US			1000
166*4a33bea0SAnurag Kumar Vulisha 
167*4a33bea0SAnurag Kumar Vulisha struct xpsgtr_dev;
168*4a33bea0SAnurag Kumar Vulisha 
169*4a33bea0SAnurag Kumar Vulisha /**
170*4a33bea0SAnurag Kumar Vulisha  * struct xpsgtr_ssc - structure to hold SSC settings for a lane
171*4a33bea0SAnurag Kumar Vulisha  * @refclk_rate: PLL reference clock frequency
172*4a33bea0SAnurag Kumar Vulisha  * @pll_ref_clk: value to be written to register for corresponding ref clk rate
173*4a33bea0SAnurag Kumar Vulisha  * @steps: number of steps of SSC (Spread Spectrum Clock)
174*4a33bea0SAnurag Kumar Vulisha  * @step_size: step size of each step
175*4a33bea0SAnurag Kumar Vulisha  */
176*4a33bea0SAnurag Kumar Vulisha struct xpsgtr_ssc {
177*4a33bea0SAnurag Kumar Vulisha 	u32 refclk_rate;
178*4a33bea0SAnurag Kumar Vulisha 	u8  pll_ref_clk;
179*4a33bea0SAnurag Kumar Vulisha 	u32 steps;
180*4a33bea0SAnurag Kumar Vulisha 	u32 step_size;
181*4a33bea0SAnurag Kumar Vulisha };
182*4a33bea0SAnurag Kumar Vulisha 
183*4a33bea0SAnurag Kumar Vulisha /**
184*4a33bea0SAnurag Kumar Vulisha  * struct xpsgtr_phy - representation of a lane
185*4a33bea0SAnurag Kumar Vulisha  * @phy: pointer to the kernel PHY device
186*4a33bea0SAnurag Kumar Vulisha  * @type: controller which uses this lane
187*4a33bea0SAnurag Kumar Vulisha  * @lane: lane number
188*4a33bea0SAnurag Kumar Vulisha  * @protocol: protocol in which the lane operates
189*4a33bea0SAnurag Kumar Vulisha  * @skip_phy_init: skip phy_init() if true
190*4a33bea0SAnurag Kumar Vulisha  * @dev: pointer to the xpsgtr_dev instance
191*4a33bea0SAnurag Kumar Vulisha  * @refclk: reference clock index
192*4a33bea0SAnurag Kumar Vulisha  */
193*4a33bea0SAnurag Kumar Vulisha struct xpsgtr_phy {
194*4a33bea0SAnurag Kumar Vulisha 	struct phy *phy;
195*4a33bea0SAnurag Kumar Vulisha 	u8 type;
196*4a33bea0SAnurag Kumar Vulisha 	u8 lane;
197*4a33bea0SAnurag Kumar Vulisha 	u8 protocol;
198*4a33bea0SAnurag Kumar Vulisha 	bool skip_phy_init;
199*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *dev;
200*4a33bea0SAnurag Kumar Vulisha 	unsigned int refclk;
201*4a33bea0SAnurag Kumar Vulisha };
202*4a33bea0SAnurag Kumar Vulisha 
203*4a33bea0SAnurag Kumar Vulisha /**
204*4a33bea0SAnurag Kumar Vulisha  * struct xpsgtr_dev - representation of a ZynMP GT device
205*4a33bea0SAnurag Kumar Vulisha  * @dev: pointer to device
206*4a33bea0SAnurag Kumar Vulisha  * @serdes: serdes base address
207*4a33bea0SAnurag Kumar Vulisha  * @siou: siou base address
208*4a33bea0SAnurag Kumar Vulisha  * @gtr_mutex: mutex for locking
209*4a33bea0SAnurag Kumar Vulisha  * @phys: PHY lanes
210*4a33bea0SAnurag Kumar Vulisha  * @refclk_sscs: spread spectrum settings for the reference clocks
211*4a33bea0SAnurag Kumar Vulisha  * @tx_term_fix: fix for GT issue
212*4a33bea0SAnurag Kumar Vulisha  * @saved_icm_cfg0: stored value of ICM CFG0 register
213*4a33bea0SAnurag Kumar Vulisha  * @saved_icm_cfg1: stored value of ICM CFG1 register
214*4a33bea0SAnurag Kumar Vulisha  */
215*4a33bea0SAnurag Kumar Vulisha struct xpsgtr_dev {
216*4a33bea0SAnurag Kumar Vulisha 	struct device *dev;
217*4a33bea0SAnurag Kumar Vulisha 	void __iomem *serdes;
218*4a33bea0SAnurag Kumar Vulisha 	void __iomem *siou;
219*4a33bea0SAnurag Kumar Vulisha 	struct mutex gtr_mutex; /* mutex for locking */
220*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy phys[NUM_LANES];
221*4a33bea0SAnurag Kumar Vulisha 	const struct xpsgtr_ssc *refclk_sscs[NUM_LANES];
222*4a33bea0SAnurag Kumar Vulisha 	bool tx_term_fix;
223*4a33bea0SAnurag Kumar Vulisha 	unsigned int saved_icm_cfg0;
224*4a33bea0SAnurag Kumar Vulisha 	unsigned int saved_icm_cfg1;
225*4a33bea0SAnurag Kumar Vulisha };
226*4a33bea0SAnurag Kumar Vulisha 
227*4a33bea0SAnurag Kumar Vulisha /*
228*4a33bea0SAnurag Kumar Vulisha  * Configuration Data
229*4a33bea0SAnurag Kumar Vulisha  */
230*4a33bea0SAnurag Kumar Vulisha 
231*4a33bea0SAnurag Kumar Vulisha /* lookup table to hold all settings needed for a ref clock frequency */
232*4a33bea0SAnurag Kumar Vulisha static const struct xpsgtr_ssc ssc_lookup[] = {
233*4a33bea0SAnurag Kumar Vulisha 	{  19200000, 0x05,  608, 264020 },
234*4a33bea0SAnurag Kumar Vulisha 	{  20000000, 0x06,  634, 243454 },
235*4a33bea0SAnurag Kumar Vulisha 	{  24000000, 0x07,  760, 168973 },
236*4a33bea0SAnurag Kumar Vulisha 	{  26000000, 0x08,  824, 143860 },
237*4a33bea0SAnurag Kumar Vulisha 	{  27000000, 0x09,  856,  86551 },
238*4a33bea0SAnurag Kumar Vulisha 	{  38400000, 0x0a, 1218,  65896 },
239*4a33bea0SAnurag Kumar Vulisha 	{  40000000, 0x0b,  634, 243454 },
240*4a33bea0SAnurag Kumar Vulisha 	{  52000000, 0x0c,  824, 143860 },
241*4a33bea0SAnurag Kumar Vulisha 	{ 100000000, 0x0d, 1058,  87533 },
242*4a33bea0SAnurag Kumar Vulisha 	{ 108000000, 0x0e,  856,  86551 },
243*4a33bea0SAnurag Kumar Vulisha 	{ 125000000, 0x0f,  992, 119497 },
244*4a33bea0SAnurag Kumar Vulisha 	{ 135000000, 0x10, 1070,  55393 },
245*4a33bea0SAnurag Kumar Vulisha 	{ 150000000, 0x11,  792, 187091 }
246*4a33bea0SAnurag Kumar Vulisha };
247*4a33bea0SAnurag Kumar Vulisha 
248*4a33bea0SAnurag Kumar Vulisha /*
249*4a33bea0SAnurag Kumar Vulisha  * I/O Accessors
250*4a33bea0SAnurag Kumar Vulisha  */
251*4a33bea0SAnurag Kumar Vulisha 
252*4a33bea0SAnurag Kumar Vulisha static inline u32 xpsgtr_read(struct xpsgtr_dev *gtr_dev, u32 reg)
253*4a33bea0SAnurag Kumar Vulisha {
254*4a33bea0SAnurag Kumar Vulisha 	return readl(gtr_dev->serdes + reg);
255*4a33bea0SAnurag Kumar Vulisha }
256*4a33bea0SAnurag Kumar Vulisha 
257*4a33bea0SAnurag Kumar Vulisha static inline void xpsgtr_write(struct xpsgtr_dev *gtr_dev, u32 reg, u32 value)
258*4a33bea0SAnurag Kumar Vulisha {
259*4a33bea0SAnurag Kumar Vulisha 	writel(value, gtr_dev->serdes + reg);
260*4a33bea0SAnurag Kumar Vulisha }
261*4a33bea0SAnurag Kumar Vulisha 
262*4a33bea0SAnurag Kumar Vulisha static inline void xpsgtr_clr_set(struct xpsgtr_dev *gtr_dev, u32 reg,
263*4a33bea0SAnurag Kumar Vulisha 				  u32 clr, u32 set)
264*4a33bea0SAnurag Kumar Vulisha {
265*4a33bea0SAnurag Kumar Vulisha 	u32 value = xpsgtr_read(gtr_dev, reg);
266*4a33bea0SAnurag Kumar Vulisha 
267*4a33bea0SAnurag Kumar Vulisha 	value &= ~clr;
268*4a33bea0SAnurag Kumar Vulisha 	value |= set;
269*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, reg, value);
270*4a33bea0SAnurag Kumar Vulisha }
271*4a33bea0SAnurag Kumar Vulisha 
272*4a33bea0SAnurag Kumar Vulisha static inline u32 xpsgtr_read_phy(struct xpsgtr_phy *gtr_phy, u32 reg)
273*4a33bea0SAnurag Kumar Vulisha {
274*4a33bea0SAnurag Kumar Vulisha 	void __iomem *addr = gtr_phy->dev->serdes
275*4a33bea0SAnurag Kumar Vulisha 			   + gtr_phy->lane * PHY_REG_OFFSET + reg;
276*4a33bea0SAnurag Kumar Vulisha 
277*4a33bea0SAnurag Kumar Vulisha 	return readl(addr);
278*4a33bea0SAnurag Kumar Vulisha }
279*4a33bea0SAnurag Kumar Vulisha 
280*4a33bea0SAnurag Kumar Vulisha static inline void xpsgtr_write_phy(struct xpsgtr_phy *gtr_phy,
281*4a33bea0SAnurag Kumar Vulisha 				    u32 reg, u32 value)
282*4a33bea0SAnurag Kumar Vulisha {
283*4a33bea0SAnurag Kumar Vulisha 	void __iomem *addr = gtr_phy->dev->serdes
284*4a33bea0SAnurag Kumar Vulisha 			   + gtr_phy->lane * PHY_REG_OFFSET + reg;
285*4a33bea0SAnurag Kumar Vulisha 
286*4a33bea0SAnurag Kumar Vulisha 	writel(value, addr);
287*4a33bea0SAnurag Kumar Vulisha }
288*4a33bea0SAnurag Kumar Vulisha 
289*4a33bea0SAnurag Kumar Vulisha static inline void xpsgtr_clr_set_phy(struct xpsgtr_phy *gtr_phy,
290*4a33bea0SAnurag Kumar Vulisha 				      u32 reg, u32 clr, u32 set)
291*4a33bea0SAnurag Kumar Vulisha {
292*4a33bea0SAnurag Kumar Vulisha 	void __iomem *addr = gtr_phy->dev->serdes
293*4a33bea0SAnurag Kumar Vulisha 			   + gtr_phy->lane * PHY_REG_OFFSET + reg;
294*4a33bea0SAnurag Kumar Vulisha 
295*4a33bea0SAnurag Kumar Vulisha 	writel((readl(addr) & ~clr) | set, addr);
296*4a33bea0SAnurag Kumar Vulisha }
297*4a33bea0SAnurag Kumar Vulisha 
298*4a33bea0SAnurag Kumar Vulisha /*
299*4a33bea0SAnurag Kumar Vulisha  * Hardware Configuration
300*4a33bea0SAnurag Kumar Vulisha  */
301*4a33bea0SAnurag Kumar Vulisha 
302*4a33bea0SAnurag Kumar Vulisha /* Wait for the PLL to lock (with a timeout). */
303*4a33bea0SAnurag Kumar Vulisha static int xpsgtr_wait_pll_lock(struct phy *phy)
304*4a33bea0SAnurag Kumar Vulisha {
305*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
306*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
307*4a33bea0SAnurag Kumar Vulisha 	unsigned int timeout = TIMEOUT_US;
308*4a33bea0SAnurag Kumar Vulisha 	int ret;
309*4a33bea0SAnurag Kumar Vulisha 
310*4a33bea0SAnurag Kumar Vulisha 	dev_dbg(gtr_dev->dev, "Waiting for PLL lock\n");
311*4a33bea0SAnurag Kumar Vulisha 
312*4a33bea0SAnurag Kumar Vulisha 	while (1) {
313*4a33bea0SAnurag Kumar Vulisha 		u32 reg = xpsgtr_read_phy(gtr_phy, L0_PLL_STATUS_READ_1);
314*4a33bea0SAnurag Kumar Vulisha 
315*4a33bea0SAnurag Kumar Vulisha 		if ((reg & PLL_STATUS_LOCKED) == PLL_STATUS_LOCKED) {
316*4a33bea0SAnurag Kumar Vulisha 			ret = 0;
317*4a33bea0SAnurag Kumar Vulisha 			break;
318*4a33bea0SAnurag Kumar Vulisha 		}
319*4a33bea0SAnurag Kumar Vulisha 
320*4a33bea0SAnurag Kumar Vulisha 		if (--timeout == 0) {
321*4a33bea0SAnurag Kumar Vulisha 			ret = -ETIMEDOUT;
322*4a33bea0SAnurag Kumar Vulisha 			break;
323*4a33bea0SAnurag Kumar Vulisha 		}
324*4a33bea0SAnurag Kumar Vulisha 
325*4a33bea0SAnurag Kumar Vulisha 		udelay(1);
326*4a33bea0SAnurag Kumar Vulisha 	}
327*4a33bea0SAnurag Kumar Vulisha 
328*4a33bea0SAnurag Kumar Vulisha 	if (ret == -ETIMEDOUT)
329*4a33bea0SAnurag Kumar Vulisha 		dev_err(gtr_dev->dev,
330*4a33bea0SAnurag Kumar Vulisha 			"lane %u (type %u, protocol %u): PLL lock timeout\n",
331*4a33bea0SAnurag Kumar Vulisha 			gtr_phy->lane, gtr_phy->type, gtr_phy->protocol);
332*4a33bea0SAnurag Kumar Vulisha 
333*4a33bea0SAnurag Kumar Vulisha 	return ret;
334*4a33bea0SAnurag Kumar Vulisha }
335*4a33bea0SAnurag Kumar Vulisha 
336*4a33bea0SAnurag Kumar Vulisha /* Configure PLL and spread-sprectrum clock. */
337*4a33bea0SAnurag Kumar Vulisha static void xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy)
338*4a33bea0SAnurag Kumar Vulisha {
339*4a33bea0SAnurag Kumar Vulisha 	const struct xpsgtr_ssc *ssc;
340*4a33bea0SAnurag Kumar Vulisha 	u32 step_size;
341*4a33bea0SAnurag Kumar Vulisha 
342*4a33bea0SAnurag Kumar Vulisha 	ssc = gtr_phy->dev->refclk_sscs[gtr_phy->refclk];
343*4a33bea0SAnurag Kumar Vulisha 	step_size = ssc->step_size;
344*4a33bea0SAnurag Kumar Vulisha 
345*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_phy->dev, PLL_REF_SEL(gtr_phy->lane),
346*4a33bea0SAnurag Kumar Vulisha 		       PLL_FREQ_MASK, ssc->pll_ref_clk);
347*4a33bea0SAnurag Kumar Vulisha 
348*4a33bea0SAnurag Kumar Vulisha 	/* Enable lane clock sharing, if required */
349*4a33bea0SAnurag Kumar Vulisha 	if (gtr_phy->refclk != gtr_phy->lane) {
350*4a33bea0SAnurag Kumar Vulisha 		/* Lane3 Ref Clock Selection Register */
351*4a33bea0SAnurag Kumar Vulisha 		xpsgtr_clr_set(gtr_phy->dev, L0_Ln_REF_CLK_SEL(gtr_phy->lane),
352*4a33bea0SAnurag Kumar Vulisha 			       L0_REF_CLK_SEL_MASK, 1 << gtr_phy->refclk);
353*4a33bea0SAnurag Kumar Vulisha 	}
354*4a33bea0SAnurag Kumar Vulisha 
355*4a33bea0SAnurag Kumar Vulisha 	/* SSC step size [7:0] */
356*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_0_LSB,
357*4a33bea0SAnurag Kumar Vulisha 			   STEP_SIZE_0_MASK, step_size & STEP_SIZE_0_MASK);
358*4a33bea0SAnurag Kumar Vulisha 
359*4a33bea0SAnurag Kumar Vulisha 	/* SSC step size [15:8] */
360*4a33bea0SAnurag Kumar Vulisha 	step_size >>= STEP_SIZE_SHIFT;
361*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_1,
362*4a33bea0SAnurag Kumar Vulisha 			   STEP_SIZE_1_MASK, step_size & STEP_SIZE_1_MASK);
363*4a33bea0SAnurag Kumar Vulisha 
364*4a33bea0SAnurag Kumar Vulisha 	/* SSC step size [23:16] */
365*4a33bea0SAnurag Kumar Vulisha 	step_size >>= STEP_SIZE_SHIFT;
366*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_2,
367*4a33bea0SAnurag Kumar Vulisha 			   STEP_SIZE_2_MASK, step_size & STEP_SIZE_2_MASK);
368*4a33bea0SAnurag Kumar Vulisha 
369*4a33bea0SAnurag Kumar Vulisha 	/* SSC steps [7:0] */
370*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEPS_0_LSB,
371*4a33bea0SAnurag Kumar Vulisha 			   STEPS_0_MASK, ssc->steps & STEPS_0_MASK);
372*4a33bea0SAnurag Kumar Vulisha 
373*4a33bea0SAnurag Kumar Vulisha 	/* SSC steps [10:8] */
374*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEPS_1_MSB,
375*4a33bea0SAnurag Kumar Vulisha 			   STEPS_1_MASK,
376*4a33bea0SAnurag Kumar Vulisha 			   (ssc->steps >> STEP_SIZE_SHIFT) & STEPS_1_MASK);
377*4a33bea0SAnurag Kumar Vulisha 
378*4a33bea0SAnurag Kumar Vulisha 	/* SSC step size [24:25] */
379*4a33bea0SAnurag Kumar Vulisha 	step_size >>= STEP_SIZE_SHIFT;
380*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_3_MSB,
381*4a33bea0SAnurag Kumar Vulisha 			   STEP_SIZE_3_MASK, (step_size & STEP_SIZE_3_MASK) |
382*4a33bea0SAnurag Kumar Vulisha 			   FORCE_STEP_SIZE | FORCE_STEPS);
383*4a33bea0SAnurag Kumar Vulisha }
384*4a33bea0SAnurag Kumar Vulisha 
385*4a33bea0SAnurag Kumar Vulisha /* Configure the lane protocol. */
386*4a33bea0SAnurag Kumar Vulisha static void xpsgtr_lane_set_protocol(struct xpsgtr_phy *gtr_phy)
387*4a33bea0SAnurag Kumar Vulisha {
388*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
389*4a33bea0SAnurag Kumar Vulisha 	u8 protocol = gtr_phy->protocol;
390*4a33bea0SAnurag Kumar Vulisha 
391*4a33bea0SAnurag Kumar Vulisha 	switch (gtr_phy->lane) {
392*4a33bea0SAnurag Kumar Vulisha 	case 0:
393*4a33bea0SAnurag Kumar Vulisha 		xpsgtr_clr_set(gtr_dev, ICM_CFG0, ICM_CFG0_L0_MASK, protocol);
394*4a33bea0SAnurag Kumar Vulisha 		break;
395*4a33bea0SAnurag Kumar Vulisha 	case 1:
396*4a33bea0SAnurag Kumar Vulisha 		xpsgtr_clr_set(gtr_dev, ICM_CFG0, ICM_CFG0_L1_MASK,
397*4a33bea0SAnurag Kumar Vulisha 			       protocol << ICM_CFG_SHIFT);
398*4a33bea0SAnurag Kumar Vulisha 		break;
399*4a33bea0SAnurag Kumar Vulisha 	case 2:
400*4a33bea0SAnurag Kumar Vulisha 		xpsgtr_clr_set(gtr_dev, ICM_CFG1, ICM_CFG0_L0_MASK, protocol);
401*4a33bea0SAnurag Kumar Vulisha 		break;
402*4a33bea0SAnurag Kumar Vulisha 	case 3:
403*4a33bea0SAnurag Kumar Vulisha 		xpsgtr_clr_set(gtr_dev, ICM_CFG1, ICM_CFG0_L1_MASK,
404*4a33bea0SAnurag Kumar Vulisha 			       protocol << ICM_CFG_SHIFT);
405*4a33bea0SAnurag Kumar Vulisha 		break;
406*4a33bea0SAnurag Kumar Vulisha 	default:
407*4a33bea0SAnurag Kumar Vulisha 		/* We already checked 0 <= lane <= 3 */
408*4a33bea0SAnurag Kumar Vulisha 		break;
409*4a33bea0SAnurag Kumar Vulisha 	}
410*4a33bea0SAnurag Kumar Vulisha }
411*4a33bea0SAnurag Kumar Vulisha 
412*4a33bea0SAnurag Kumar Vulisha /* Bypass (de)scrambler and 8b/10b decoder and encoder. */
413*4a33bea0SAnurag Kumar Vulisha static void xpsgtr_bypass_scrambler_8b10b(struct xpsgtr_phy *gtr_phy)
414*4a33bea0SAnurag Kumar Vulisha {
415*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TM_DIG_6, L0_TM_DIS_DESCRAMBLE_DECODER);
416*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TX_DIG_61, L0_TM_DISABLE_SCRAMBLE_ENCODER);
417*4a33bea0SAnurag Kumar Vulisha }
418*4a33bea0SAnurag Kumar Vulisha 
419*4a33bea0SAnurag Kumar Vulisha /* DP-specific initialization. */
420*4a33bea0SAnurag Kumar Vulisha static void xpsgtr_phy_init_dp(struct xpsgtr_phy *gtr_phy)
421*4a33bea0SAnurag Kumar Vulisha {
422*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TXPMD_TM_45,
423*4a33bea0SAnurag Kumar Vulisha 			 L0_TXPMD_TM_45_OVER_DP_MAIN |
424*4a33bea0SAnurag Kumar Vulisha 			 L0_TXPMD_TM_45_ENABLE_DP_MAIN |
425*4a33bea0SAnurag Kumar Vulisha 			 L0_TXPMD_TM_45_OVER_DP_POST1 |
426*4a33bea0SAnurag Kumar Vulisha 			 L0_TXPMD_TM_45_OVER_DP_POST2 |
427*4a33bea0SAnurag Kumar Vulisha 			 L0_TXPMD_TM_45_ENABLE_DP_POST2);
428*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TX_ANA_TM_118,
429*4a33bea0SAnurag Kumar Vulisha 			 L0_TX_ANA_TM_118_FORCE_17_0);
430*4a33bea0SAnurag Kumar Vulisha }
431*4a33bea0SAnurag Kumar Vulisha 
432*4a33bea0SAnurag Kumar Vulisha /* SATA-specific initialization. */
433*4a33bea0SAnurag Kumar Vulisha static void xpsgtr_phy_init_sata(struct xpsgtr_phy *gtr_phy)
434*4a33bea0SAnurag Kumar Vulisha {
435*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
436*4a33bea0SAnurag Kumar Vulisha 
437*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_bypass_scrambler_8b10b(gtr_phy);
438*4a33bea0SAnurag Kumar Vulisha 
439*4a33bea0SAnurag Kumar Vulisha 	writel(gtr_phy->lane, gtr_dev->siou + SATA_CONTROL_OFFSET);
440*4a33bea0SAnurag Kumar Vulisha }
441*4a33bea0SAnurag Kumar Vulisha 
442*4a33bea0SAnurag Kumar Vulisha /* SGMII-specific initialization. */
443*4a33bea0SAnurag Kumar Vulisha static void xpsgtr_phy_init_sgmii(struct xpsgtr_phy *gtr_phy)
444*4a33bea0SAnurag Kumar Vulisha {
445*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
446*4a33bea0SAnurag Kumar Vulisha 
447*4a33bea0SAnurag Kumar Vulisha 	/* Set SGMII protocol TX and RX bus width to 10 bits. */
448*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, TX_PROT_BUS_WIDTH,
449*4a33bea0SAnurag Kumar Vulisha 		     PROT_BUS_WIDTH_10 << (gtr_phy->lane * PROT_BUS_WIDTH_SHIFT));
450*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, RX_PROT_BUS_WIDTH,
451*4a33bea0SAnurag Kumar Vulisha 		     PROT_BUS_WIDTH_10 << (gtr_phy->lane * PROT_BUS_WIDTH_SHIFT));
452*4a33bea0SAnurag Kumar Vulisha 
453*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_bypass_scrambler_8b10b(gtr_phy);
454*4a33bea0SAnurag Kumar Vulisha }
455*4a33bea0SAnurag Kumar Vulisha 
456*4a33bea0SAnurag Kumar Vulisha /* Configure TX de-emphasis and margining for DP. */
457*4a33bea0SAnurag Kumar Vulisha static void xpsgtr_phy_configure_dp(struct xpsgtr_phy *gtr_phy, unsigned int pre,
458*4a33bea0SAnurag Kumar Vulisha 				    unsigned int voltage)
459*4a33bea0SAnurag Kumar Vulisha {
460*4a33bea0SAnurag Kumar Vulisha 	static const u8 voltage_swing[4][4] = {
461*4a33bea0SAnurag Kumar Vulisha 		{ 0x2a, 0x27, 0x24, 0x20 },
462*4a33bea0SAnurag Kumar Vulisha 		{ 0x27, 0x23, 0x20, 0xff },
463*4a33bea0SAnurag Kumar Vulisha 		{ 0x24, 0x20, 0xff, 0xff },
464*4a33bea0SAnurag Kumar Vulisha 		{ 0xff, 0xff, 0xff, 0xff }
465*4a33bea0SAnurag Kumar Vulisha 	};
466*4a33bea0SAnurag Kumar Vulisha 	static const u8 pre_emphasis[4][4] = {
467*4a33bea0SAnurag Kumar Vulisha 		{ 0x02, 0x02, 0x02, 0x02 },
468*4a33bea0SAnurag Kumar Vulisha 		{ 0x01, 0x01, 0x01, 0xff },
469*4a33bea0SAnurag Kumar Vulisha 		{ 0x00, 0x00, 0xff, 0xff },
470*4a33bea0SAnurag Kumar Vulisha 		{ 0xff, 0xff, 0xff, 0xff }
471*4a33bea0SAnurag Kumar Vulisha 	};
472*4a33bea0SAnurag Kumar Vulisha 
473*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TXPMD_TM_48, voltage_swing[pre][voltage]);
474*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TX_ANA_TM_18, pre_emphasis[pre][voltage]);
475*4a33bea0SAnurag Kumar Vulisha }
476*4a33bea0SAnurag Kumar Vulisha 
477*4a33bea0SAnurag Kumar Vulisha /*
478*4a33bea0SAnurag Kumar Vulisha  * PHY Operations
479*4a33bea0SAnurag Kumar Vulisha  */
480*4a33bea0SAnurag Kumar Vulisha 
481*4a33bea0SAnurag Kumar Vulisha static bool xpsgtr_phy_init_required(struct xpsgtr_phy *gtr_phy)
482*4a33bea0SAnurag Kumar Vulisha {
483*4a33bea0SAnurag Kumar Vulisha 	/*
484*4a33bea0SAnurag Kumar Vulisha 	 * As USB may save the snapshot of the states during hibernation, doing
485*4a33bea0SAnurag Kumar Vulisha 	 * phy_init() will put the USB controller into reset, resulting in the
486*4a33bea0SAnurag Kumar Vulisha 	 * losing of the saved snapshot. So try to avoid phy_init() for USB
487*4a33bea0SAnurag Kumar Vulisha 	 * except when gtr_phy->skip_phy_init is false (this happens when FPD is
488*4a33bea0SAnurag Kumar Vulisha 	 * shutdown during suspend or when gt lane is changed from current one)
489*4a33bea0SAnurag Kumar Vulisha 	 */
490*4a33bea0SAnurag Kumar Vulisha 	if (gtr_phy->protocol == ICM_PROTOCOL_USB && gtr_phy->skip_phy_init)
491*4a33bea0SAnurag Kumar Vulisha 		return false;
492*4a33bea0SAnurag Kumar Vulisha 	else
493*4a33bea0SAnurag Kumar Vulisha 		return true;
494*4a33bea0SAnurag Kumar Vulisha }
495*4a33bea0SAnurag Kumar Vulisha 
496*4a33bea0SAnurag Kumar Vulisha /*
497*4a33bea0SAnurag Kumar Vulisha  * There is a functional issue in the GT. The TX termination resistance can be
498*4a33bea0SAnurag Kumar Vulisha  * out of spec due to a issue in the calibration logic. This is the workaround
499*4a33bea0SAnurag Kumar Vulisha  * to fix it, required for XCZU9EG silicon.
500*4a33bea0SAnurag Kumar Vulisha  */
501*4a33bea0SAnurag Kumar Vulisha static int xpsgtr_phy_tx_term_fix(struct xpsgtr_phy *gtr_phy)
502*4a33bea0SAnurag Kumar Vulisha {
503*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
504*4a33bea0SAnurag Kumar Vulisha 	u32 timeout = TIMEOUT_US;
505*4a33bea0SAnurag Kumar Vulisha 	u32 nsw;
506*4a33bea0SAnurag Kumar Vulisha 
507*4a33bea0SAnurag Kumar Vulisha 	/* Enabling Test Mode control for CMN Rest */
508*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_dev, TM_CMN_RST, TM_CMN_RST_MASK, TM_CMN_RST_SET);
509*4a33bea0SAnurag Kumar Vulisha 
510*4a33bea0SAnurag Kumar Vulisha 	/* Set Test Mode reset */
511*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_dev, TM_CMN_RST, TM_CMN_RST_MASK, TM_CMN_RST_EN);
512*4a33bea0SAnurag Kumar Vulisha 
513*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, L3_TM_CALIB_DIG18, 0x00);
514*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, L3_TM_CALIB_DIG19, L3_TM_OVERRIDE_NSW_CODE);
515*4a33bea0SAnurag Kumar Vulisha 
516*4a33bea0SAnurag Kumar Vulisha 	/*
517*4a33bea0SAnurag Kumar Vulisha 	 * As a part of work around sequence for PMOS calibration fix,
518*4a33bea0SAnurag Kumar Vulisha 	 * we need to configure any lane ICM_CFG to valid protocol. This
519*4a33bea0SAnurag Kumar Vulisha 	 * will deassert the CMN_Resetn signal.
520*4a33bea0SAnurag Kumar Vulisha 	 */
521*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_lane_set_protocol(gtr_phy);
522*4a33bea0SAnurag Kumar Vulisha 
523*4a33bea0SAnurag Kumar Vulisha 	/* Clear Test Mode reset */
524*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_dev, TM_CMN_RST, TM_CMN_RST_MASK, TM_CMN_RST_SET);
525*4a33bea0SAnurag Kumar Vulisha 
526*4a33bea0SAnurag Kumar Vulisha 	dev_dbg(gtr_dev->dev, "calibrating...\n");
527*4a33bea0SAnurag Kumar Vulisha 
528*4a33bea0SAnurag Kumar Vulisha 	do {
529*4a33bea0SAnurag Kumar Vulisha 		u32 reg = xpsgtr_read(gtr_dev, L3_CALIB_DONE_STATUS);
530*4a33bea0SAnurag Kumar Vulisha 
531*4a33bea0SAnurag Kumar Vulisha 		if ((reg & L3_CALIB_DONE) == L3_CALIB_DONE)
532*4a33bea0SAnurag Kumar Vulisha 			break;
533*4a33bea0SAnurag Kumar Vulisha 
534*4a33bea0SAnurag Kumar Vulisha 		if (!--timeout) {
535*4a33bea0SAnurag Kumar Vulisha 			dev_err(gtr_dev->dev, "calibration time out\n");
536*4a33bea0SAnurag Kumar Vulisha 			return -ETIMEDOUT;
537*4a33bea0SAnurag Kumar Vulisha 		}
538*4a33bea0SAnurag Kumar Vulisha 
539*4a33bea0SAnurag Kumar Vulisha 		udelay(1);
540*4a33bea0SAnurag Kumar Vulisha 	} while (timeout > 0);
541*4a33bea0SAnurag Kumar Vulisha 
542*4a33bea0SAnurag Kumar Vulisha 	dev_dbg(gtr_dev->dev, "calibration done\n");
543*4a33bea0SAnurag Kumar Vulisha 
544*4a33bea0SAnurag Kumar Vulisha 	/* Reading NMOS Register Code */
545*4a33bea0SAnurag Kumar Vulisha 	nsw = xpsgtr_read(gtr_dev, L0_TXPMA_ST_3) & L0_DN_CALIB_CODE;
546*4a33bea0SAnurag Kumar Vulisha 
547*4a33bea0SAnurag Kumar Vulisha 	/* Set Test Mode reset */
548*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_dev, TM_CMN_RST, TM_CMN_RST_MASK, TM_CMN_RST_EN);
549*4a33bea0SAnurag Kumar Vulisha 
550*4a33bea0SAnurag Kumar Vulisha 	/* Writing NMOS register values back [5:3] */
551*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, L3_TM_CALIB_DIG19, nsw >> L3_NSW_CALIB_SHIFT);
552*4a33bea0SAnurag Kumar Vulisha 
553*4a33bea0SAnurag Kumar Vulisha 	/* Writing NMOS register value [2:0] */
554*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, L3_TM_CALIB_DIG18,
555*4a33bea0SAnurag Kumar Vulisha 		     ((nsw & L3_TM_CALIB_DIG19_NSW) << L3_NSW_SHIFT) |
556*4a33bea0SAnurag Kumar Vulisha 		     (1 << L3_NSW_PIPE_SHIFT));
557*4a33bea0SAnurag Kumar Vulisha 
558*4a33bea0SAnurag Kumar Vulisha 	/* Clear Test Mode reset */
559*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_dev, TM_CMN_RST, TM_CMN_RST_MASK, TM_CMN_RST_SET);
560*4a33bea0SAnurag Kumar Vulisha 
561*4a33bea0SAnurag Kumar Vulisha 	return 0;
562*4a33bea0SAnurag Kumar Vulisha }
563*4a33bea0SAnurag Kumar Vulisha 
564*4a33bea0SAnurag Kumar Vulisha static int xpsgtr_phy_init(struct phy *phy)
565*4a33bea0SAnurag Kumar Vulisha {
566*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
567*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
568*4a33bea0SAnurag Kumar Vulisha 	int ret = 0;
569*4a33bea0SAnurag Kumar Vulisha 
570*4a33bea0SAnurag Kumar Vulisha 	mutex_lock(&gtr_dev->gtr_mutex);
571*4a33bea0SAnurag Kumar Vulisha 
572*4a33bea0SAnurag Kumar Vulisha 	/* Skip initialization if not required. */
573*4a33bea0SAnurag Kumar Vulisha 	if (!xpsgtr_phy_init_required(gtr_phy))
574*4a33bea0SAnurag Kumar Vulisha 		goto out;
575*4a33bea0SAnurag Kumar Vulisha 
576*4a33bea0SAnurag Kumar Vulisha 	if (gtr_dev->tx_term_fix) {
577*4a33bea0SAnurag Kumar Vulisha 		ret = xpsgtr_phy_tx_term_fix(gtr_phy);
578*4a33bea0SAnurag Kumar Vulisha 		if (ret < 0)
579*4a33bea0SAnurag Kumar Vulisha 			goto out;
580*4a33bea0SAnurag Kumar Vulisha 
581*4a33bea0SAnurag Kumar Vulisha 		gtr_dev->tx_term_fix = false;
582*4a33bea0SAnurag Kumar Vulisha 	}
583*4a33bea0SAnurag Kumar Vulisha 
584*4a33bea0SAnurag Kumar Vulisha 	/* Enable coarse code saturation limiting logic. */
585*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TM_PLL_DIG_37, L0_TM_COARSE_CODE_LIMIT);
586*4a33bea0SAnurag Kumar Vulisha 
587*4a33bea0SAnurag Kumar Vulisha 	/*
588*4a33bea0SAnurag Kumar Vulisha 	 * Configure the PLL, the lane protocol, and perform protocol-specific
589*4a33bea0SAnurag Kumar Vulisha 	 * initialization.
590*4a33bea0SAnurag Kumar Vulisha 	 */
591*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_configure_pll(gtr_phy);
592*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_lane_set_protocol(gtr_phy);
593*4a33bea0SAnurag Kumar Vulisha 
594*4a33bea0SAnurag Kumar Vulisha 	switch (gtr_phy->protocol) {
595*4a33bea0SAnurag Kumar Vulisha 	case ICM_PROTOCOL_DP:
596*4a33bea0SAnurag Kumar Vulisha 		xpsgtr_phy_init_dp(gtr_phy);
597*4a33bea0SAnurag Kumar Vulisha 		break;
598*4a33bea0SAnurag Kumar Vulisha 
599*4a33bea0SAnurag Kumar Vulisha 	case ICM_PROTOCOL_SATA:
600*4a33bea0SAnurag Kumar Vulisha 		xpsgtr_phy_init_sata(gtr_phy);
601*4a33bea0SAnurag Kumar Vulisha 		break;
602*4a33bea0SAnurag Kumar Vulisha 
603*4a33bea0SAnurag Kumar Vulisha 	case ICM_PROTOCOL_SGMII:
604*4a33bea0SAnurag Kumar Vulisha 		xpsgtr_phy_init_sgmii(gtr_phy);
605*4a33bea0SAnurag Kumar Vulisha 		break;
606*4a33bea0SAnurag Kumar Vulisha 	}
607*4a33bea0SAnurag Kumar Vulisha 
608*4a33bea0SAnurag Kumar Vulisha out:
609*4a33bea0SAnurag Kumar Vulisha 	mutex_unlock(&gtr_dev->gtr_mutex);
610*4a33bea0SAnurag Kumar Vulisha 	return ret;
611*4a33bea0SAnurag Kumar Vulisha }
612*4a33bea0SAnurag Kumar Vulisha 
613*4a33bea0SAnurag Kumar Vulisha static int xpsgtr_phy_exit(struct phy *phy)
614*4a33bea0SAnurag Kumar Vulisha {
615*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
616*4a33bea0SAnurag Kumar Vulisha 
617*4a33bea0SAnurag Kumar Vulisha 	gtr_phy->skip_phy_init = false;
618*4a33bea0SAnurag Kumar Vulisha 
619*4a33bea0SAnurag Kumar Vulisha 	return 0;
620*4a33bea0SAnurag Kumar Vulisha }
621*4a33bea0SAnurag Kumar Vulisha 
622*4a33bea0SAnurag Kumar Vulisha static int xpsgtr_phy_power_on(struct phy *phy)
623*4a33bea0SAnurag Kumar Vulisha {
624*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
625*4a33bea0SAnurag Kumar Vulisha 	int ret = 0;
626*4a33bea0SAnurag Kumar Vulisha 
627*4a33bea0SAnurag Kumar Vulisha 	/*
628*4a33bea0SAnurag Kumar Vulisha 	 * Wait for the PLL to lock. For DP, only wait on DP0 to avoid
629*4a33bea0SAnurag Kumar Vulisha 	 * cumulating waits for both lanes. The user is expected to initialize
630*4a33bea0SAnurag Kumar Vulisha 	 * lane 0 last.
631*4a33bea0SAnurag Kumar Vulisha 	 */
632*4a33bea0SAnurag Kumar Vulisha 	if (gtr_phy->protocol != ICM_PROTOCOL_DP ||
633*4a33bea0SAnurag Kumar Vulisha 	    gtr_phy->type == XPSGTR_TYPE_DP_0)
634*4a33bea0SAnurag Kumar Vulisha 		ret = xpsgtr_wait_pll_lock(phy);
635*4a33bea0SAnurag Kumar Vulisha 
636*4a33bea0SAnurag Kumar Vulisha 	return ret;
637*4a33bea0SAnurag Kumar Vulisha }
638*4a33bea0SAnurag Kumar Vulisha 
639*4a33bea0SAnurag Kumar Vulisha static int xpsgtr_phy_configure(struct phy *phy, union phy_configure_opts *opts)
640*4a33bea0SAnurag Kumar Vulisha {
641*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
642*4a33bea0SAnurag Kumar Vulisha 
643*4a33bea0SAnurag Kumar Vulisha 	if (gtr_phy->protocol != ICM_PROTOCOL_DP)
644*4a33bea0SAnurag Kumar Vulisha 		return 0;
645*4a33bea0SAnurag Kumar Vulisha 
646*4a33bea0SAnurag Kumar Vulisha 	xpsgtr_phy_configure_dp(gtr_phy, opts->dp.pre[0], opts->dp.voltage[0]);
647*4a33bea0SAnurag Kumar Vulisha 
648*4a33bea0SAnurag Kumar Vulisha 	return 0;
649*4a33bea0SAnurag Kumar Vulisha }
650*4a33bea0SAnurag Kumar Vulisha 
651*4a33bea0SAnurag Kumar Vulisha static const struct phy_ops xpsgtr_phyops = {
652*4a33bea0SAnurag Kumar Vulisha 	.init		= xpsgtr_phy_init,
653*4a33bea0SAnurag Kumar Vulisha 	.exit		= xpsgtr_phy_exit,
654*4a33bea0SAnurag Kumar Vulisha 	.power_on	= xpsgtr_phy_power_on,
655*4a33bea0SAnurag Kumar Vulisha 	.configure	= xpsgtr_phy_configure,
656*4a33bea0SAnurag Kumar Vulisha 	.owner		= THIS_MODULE,
657*4a33bea0SAnurag Kumar Vulisha };
658*4a33bea0SAnurag Kumar Vulisha 
659*4a33bea0SAnurag Kumar Vulisha /*
660*4a33bea0SAnurag Kumar Vulisha  * OF Xlate Support
661*4a33bea0SAnurag Kumar Vulisha  */
662*4a33bea0SAnurag Kumar Vulisha 
663*4a33bea0SAnurag Kumar Vulisha /* Set the lane type and protocol based on the PHY type and instance number. */
664*4a33bea0SAnurag Kumar Vulisha static int xpsgtr_set_lane_type(struct xpsgtr_phy *gtr_phy, u8 phy_type,
665*4a33bea0SAnurag Kumar Vulisha 				unsigned int phy_instance)
666*4a33bea0SAnurag Kumar Vulisha {
667*4a33bea0SAnurag Kumar Vulisha 	unsigned int num_phy_types;
668*4a33bea0SAnurag Kumar Vulisha 	const int *phy_types;
669*4a33bea0SAnurag Kumar Vulisha 
670*4a33bea0SAnurag Kumar Vulisha 	switch (phy_type) {
671*4a33bea0SAnurag Kumar Vulisha 	case PHY_TYPE_SATA: {
672*4a33bea0SAnurag Kumar Vulisha 		static const int types[] = {
673*4a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_SATA_0,
674*4a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_SATA_1,
675*4a33bea0SAnurag Kumar Vulisha 		};
676*4a33bea0SAnurag Kumar Vulisha 
677*4a33bea0SAnurag Kumar Vulisha 		phy_types = types;
678*4a33bea0SAnurag Kumar Vulisha 		num_phy_types = ARRAY_SIZE(types);
679*4a33bea0SAnurag Kumar Vulisha 		gtr_phy->protocol = ICM_PROTOCOL_SATA;
680*4a33bea0SAnurag Kumar Vulisha 		break;
681*4a33bea0SAnurag Kumar Vulisha 	}
682*4a33bea0SAnurag Kumar Vulisha 	case PHY_TYPE_USB3: {
683*4a33bea0SAnurag Kumar Vulisha 		static const int types[] = {
684*4a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_USB0,
685*4a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_USB1,
686*4a33bea0SAnurag Kumar Vulisha 		};
687*4a33bea0SAnurag Kumar Vulisha 
688*4a33bea0SAnurag Kumar Vulisha 		phy_types = types;
689*4a33bea0SAnurag Kumar Vulisha 		num_phy_types = ARRAY_SIZE(types);
690*4a33bea0SAnurag Kumar Vulisha 		gtr_phy->protocol = ICM_PROTOCOL_USB;
691*4a33bea0SAnurag Kumar Vulisha 		break;
692*4a33bea0SAnurag Kumar Vulisha 	}
693*4a33bea0SAnurag Kumar Vulisha 	case PHY_TYPE_DP: {
694*4a33bea0SAnurag Kumar Vulisha 		static const int types[] = {
695*4a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_DP_0,
696*4a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_DP_1,
697*4a33bea0SAnurag Kumar Vulisha 		};
698*4a33bea0SAnurag Kumar Vulisha 
699*4a33bea0SAnurag Kumar Vulisha 		phy_types = types;
700*4a33bea0SAnurag Kumar Vulisha 		num_phy_types = ARRAY_SIZE(types);
701*4a33bea0SAnurag Kumar Vulisha 		gtr_phy->protocol = ICM_PROTOCOL_DP;
702*4a33bea0SAnurag Kumar Vulisha 		break;
703*4a33bea0SAnurag Kumar Vulisha 	}
704*4a33bea0SAnurag Kumar Vulisha 	case PHY_TYPE_PCIE: {
705*4a33bea0SAnurag Kumar Vulisha 		static const int types[] = {
706*4a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_PCIE_0,
707*4a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_PCIE_1,
708*4a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_PCIE_2,
709*4a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_PCIE_3,
710*4a33bea0SAnurag Kumar Vulisha 		};
711*4a33bea0SAnurag Kumar Vulisha 
712*4a33bea0SAnurag Kumar Vulisha 		phy_types = types;
713*4a33bea0SAnurag Kumar Vulisha 		num_phy_types = ARRAY_SIZE(types);
714*4a33bea0SAnurag Kumar Vulisha 		gtr_phy->protocol = ICM_PROTOCOL_PCIE;
715*4a33bea0SAnurag Kumar Vulisha 		break;
716*4a33bea0SAnurag Kumar Vulisha 	}
717*4a33bea0SAnurag Kumar Vulisha 	case PHY_TYPE_SGMII: {
718*4a33bea0SAnurag Kumar Vulisha 		static const int types[] = {
719*4a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_SGMII0,
720*4a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_SGMII1,
721*4a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_SGMII2,
722*4a33bea0SAnurag Kumar Vulisha 			XPSGTR_TYPE_SGMII3,
723*4a33bea0SAnurag Kumar Vulisha 		};
724*4a33bea0SAnurag Kumar Vulisha 
725*4a33bea0SAnurag Kumar Vulisha 		phy_types = types;
726*4a33bea0SAnurag Kumar Vulisha 		num_phy_types = ARRAY_SIZE(types);
727*4a33bea0SAnurag Kumar Vulisha 		gtr_phy->protocol = ICM_PROTOCOL_SGMII;
728*4a33bea0SAnurag Kumar Vulisha 		break;
729*4a33bea0SAnurag Kumar Vulisha 	}
730*4a33bea0SAnurag Kumar Vulisha 	default:
731*4a33bea0SAnurag Kumar Vulisha 		return -EINVAL;
732*4a33bea0SAnurag Kumar Vulisha 	}
733*4a33bea0SAnurag Kumar Vulisha 
734*4a33bea0SAnurag Kumar Vulisha 	if (phy_instance >= num_phy_types)
735*4a33bea0SAnurag Kumar Vulisha 		return -EINVAL;
736*4a33bea0SAnurag Kumar Vulisha 
737*4a33bea0SAnurag Kumar Vulisha 	gtr_phy->type = phy_types[phy_instance];
738*4a33bea0SAnurag Kumar Vulisha 	return 0;
739*4a33bea0SAnurag Kumar Vulisha }
740*4a33bea0SAnurag Kumar Vulisha 
741*4a33bea0SAnurag Kumar Vulisha /*
742*4a33bea0SAnurag Kumar Vulisha  * Valid combinations of controllers and lanes (Interconnect Matrix).
743*4a33bea0SAnurag Kumar Vulisha  */
744*4a33bea0SAnurag Kumar Vulisha static const unsigned int icm_matrix[NUM_LANES][CONTROLLERS_PER_LANE] = {
745*4a33bea0SAnurag Kumar Vulisha 	{ XPSGTR_TYPE_PCIE_0, XPSGTR_TYPE_SATA_0, XPSGTR_TYPE_USB0,
746*4a33bea0SAnurag Kumar Vulisha 		XPSGTR_TYPE_DP_1, XPSGTR_TYPE_SGMII0 },
747*4a33bea0SAnurag Kumar Vulisha 	{ XPSGTR_TYPE_PCIE_1, XPSGTR_TYPE_SATA_1, XPSGTR_TYPE_USB0,
748*4a33bea0SAnurag Kumar Vulisha 		XPSGTR_TYPE_DP_0, XPSGTR_TYPE_SGMII1 },
749*4a33bea0SAnurag Kumar Vulisha 	{ XPSGTR_TYPE_PCIE_2, XPSGTR_TYPE_SATA_0, XPSGTR_TYPE_USB0,
750*4a33bea0SAnurag Kumar Vulisha 		XPSGTR_TYPE_DP_1, XPSGTR_TYPE_SGMII2 },
751*4a33bea0SAnurag Kumar Vulisha 	{ XPSGTR_TYPE_PCIE_3, XPSGTR_TYPE_SATA_1, XPSGTR_TYPE_USB1,
752*4a33bea0SAnurag Kumar Vulisha 		XPSGTR_TYPE_DP_0, XPSGTR_TYPE_SGMII3 }
753*4a33bea0SAnurag Kumar Vulisha };
754*4a33bea0SAnurag Kumar Vulisha 
755*4a33bea0SAnurag Kumar Vulisha /* Translate OF phandle and args to PHY instance. */
756*4a33bea0SAnurag Kumar Vulisha static struct phy *xpsgtr_xlate(struct device *dev,
757*4a33bea0SAnurag Kumar Vulisha 				struct of_phandle_args *args)
758*4a33bea0SAnurag Kumar Vulisha {
759*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev);
760*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy;
761*4a33bea0SAnurag Kumar Vulisha 	unsigned int phy_instance;
762*4a33bea0SAnurag Kumar Vulisha 	unsigned int phy_lane;
763*4a33bea0SAnurag Kumar Vulisha 	unsigned int phy_type;
764*4a33bea0SAnurag Kumar Vulisha 	unsigned int refclk;
765*4a33bea0SAnurag Kumar Vulisha 	unsigned int i;
766*4a33bea0SAnurag Kumar Vulisha 	int ret;
767*4a33bea0SAnurag Kumar Vulisha 
768*4a33bea0SAnurag Kumar Vulisha 	if (args->args_count != 4) {
769*4a33bea0SAnurag Kumar Vulisha 		dev_err(dev, "Invalid number of cells in 'phy' property\n");
770*4a33bea0SAnurag Kumar Vulisha 		return ERR_PTR(-EINVAL);
771*4a33bea0SAnurag Kumar Vulisha 	}
772*4a33bea0SAnurag Kumar Vulisha 
773*4a33bea0SAnurag Kumar Vulisha 	/*
774*4a33bea0SAnurag Kumar Vulisha 	 * Get the PHY parameters from the OF arguments and derive the lane
775*4a33bea0SAnurag Kumar Vulisha 	 * type.
776*4a33bea0SAnurag Kumar Vulisha 	 */
777*4a33bea0SAnurag Kumar Vulisha 	phy_lane = args->args[0];
778*4a33bea0SAnurag Kumar Vulisha 	if (phy_lane >= ARRAY_SIZE(gtr_dev->phys)) {
779*4a33bea0SAnurag Kumar Vulisha 		dev_err(dev, "Invalid lane number %u\n", phy_lane);
780*4a33bea0SAnurag Kumar Vulisha 		return ERR_PTR(-ENODEV);
781*4a33bea0SAnurag Kumar Vulisha 	}
782*4a33bea0SAnurag Kumar Vulisha 
783*4a33bea0SAnurag Kumar Vulisha 	gtr_phy = &gtr_dev->phys[phy_lane];
784*4a33bea0SAnurag Kumar Vulisha 	phy_type = args->args[1];
785*4a33bea0SAnurag Kumar Vulisha 	phy_instance = args->args[2];
786*4a33bea0SAnurag Kumar Vulisha 
787*4a33bea0SAnurag Kumar Vulisha 	ret = xpsgtr_set_lane_type(gtr_phy, phy_type, phy_instance);
788*4a33bea0SAnurag Kumar Vulisha 	if (ret < 0) {
789*4a33bea0SAnurag Kumar Vulisha 		dev_err(gtr_dev->dev, "Invalid PHY type and/or instance\n");
790*4a33bea0SAnurag Kumar Vulisha 		return ERR_PTR(ret);
791*4a33bea0SAnurag Kumar Vulisha 	}
792*4a33bea0SAnurag Kumar Vulisha 
793*4a33bea0SAnurag Kumar Vulisha 	refclk = args->args[3];
794*4a33bea0SAnurag Kumar Vulisha 	if (refclk >= ARRAY_SIZE(gtr_dev->refclk_sscs) ||
795*4a33bea0SAnurag Kumar Vulisha 	    !gtr_dev->refclk_sscs[refclk]) {
796*4a33bea0SAnurag Kumar Vulisha 		dev_err(dev, "Invalid reference clock number %u\n", refclk);
797*4a33bea0SAnurag Kumar Vulisha 		return ERR_PTR(-EINVAL);
798*4a33bea0SAnurag Kumar Vulisha 	}
799*4a33bea0SAnurag Kumar Vulisha 
800*4a33bea0SAnurag Kumar Vulisha 	gtr_phy->refclk = refclk;
801*4a33bea0SAnurag Kumar Vulisha 
802*4a33bea0SAnurag Kumar Vulisha 	/*
803*4a33bea0SAnurag Kumar Vulisha 	 * Ensure that the Interconnect Matrix is obeyed, i.e a given lane type
804*4a33bea0SAnurag Kumar Vulisha 	 * is allowed to operate on the lane.
805*4a33bea0SAnurag Kumar Vulisha 	 */
806*4a33bea0SAnurag Kumar Vulisha 	for (i = 0; i < CONTROLLERS_PER_LANE; i++) {
807*4a33bea0SAnurag Kumar Vulisha 		if (icm_matrix[phy_lane][i] == gtr_phy->type)
808*4a33bea0SAnurag Kumar Vulisha 			return gtr_phy->phy;
809*4a33bea0SAnurag Kumar Vulisha 	}
810*4a33bea0SAnurag Kumar Vulisha 
811*4a33bea0SAnurag Kumar Vulisha 	return ERR_PTR(-EINVAL);
812*4a33bea0SAnurag Kumar Vulisha }
813*4a33bea0SAnurag Kumar Vulisha 
814*4a33bea0SAnurag Kumar Vulisha /*
815*4a33bea0SAnurag Kumar Vulisha  * Power Management
816*4a33bea0SAnurag Kumar Vulisha  */
817*4a33bea0SAnurag Kumar Vulisha 
818*4a33bea0SAnurag Kumar Vulisha #ifdef CONFIG_PM
819*4a33bea0SAnurag Kumar Vulisha static int xpsgtr_suspend(struct device *dev)
820*4a33bea0SAnurag Kumar Vulisha {
821*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev);
822*4a33bea0SAnurag Kumar Vulisha 
823*4a33bea0SAnurag Kumar Vulisha 	/* Save the snapshot ICM_CFG registers. */
824*4a33bea0SAnurag Kumar Vulisha 	gtr_dev->saved_icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0);
825*4a33bea0SAnurag Kumar Vulisha 	gtr_dev->saved_icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1);
826*4a33bea0SAnurag Kumar Vulisha 
827*4a33bea0SAnurag Kumar Vulisha 	return 0;
828*4a33bea0SAnurag Kumar Vulisha }
829*4a33bea0SAnurag Kumar Vulisha 
830*4a33bea0SAnurag Kumar Vulisha static int xpsgtr_resume(struct device *dev)
831*4a33bea0SAnurag Kumar Vulisha {
832*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev);
833*4a33bea0SAnurag Kumar Vulisha 	unsigned int icm_cfg0, icm_cfg1;
834*4a33bea0SAnurag Kumar Vulisha 	unsigned int i;
835*4a33bea0SAnurag Kumar Vulisha 	bool skip_phy_init;
836*4a33bea0SAnurag Kumar Vulisha 
837*4a33bea0SAnurag Kumar Vulisha 	icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0);
838*4a33bea0SAnurag Kumar Vulisha 	icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1);
839*4a33bea0SAnurag Kumar Vulisha 
840*4a33bea0SAnurag Kumar Vulisha 	/* Return if no GT lanes got configured before suspend. */
841*4a33bea0SAnurag Kumar Vulisha 	if (!gtr_dev->saved_icm_cfg0 && !gtr_dev->saved_icm_cfg1)
842*4a33bea0SAnurag Kumar Vulisha 		return 0;
843*4a33bea0SAnurag Kumar Vulisha 
844*4a33bea0SAnurag Kumar Vulisha 	/* Check if the ICM configurations changed after suspend. */
845*4a33bea0SAnurag Kumar Vulisha 	if (icm_cfg0 == gtr_dev->saved_icm_cfg0 &&
846*4a33bea0SAnurag Kumar Vulisha 	    icm_cfg1 == gtr_dev->saved_icm_cfg1)
847*4a33bea0SAnurag Kumar Vulisha 		skip_phy_init = true;
848*4a33bea0SAnurag Kumar Vulisha 	else
849*4a33bea0SAnurag Kumar Vulisha 		skip_phy_init = false;
850*4a33bea0SAnurag Kumar Vulisha 
851*4a33bea0SAnurag Kumar Vulisha 	/* Update the skip_phy_init for all gtr_phy instances. */
852*4a33bea0SAnurag Kumar Vulisha 	for (i = 0; i < ARRAY_SIZE(gtr_dev->phys); i++)
853*4a33bea0SAnurag Kumar Vulisha 		gtr_dev->phys[i].skip_phy_init = skip_phy_init;
854*4a33bea0SAnurag Kumar Vulisha 
855*4a33bea0SAnurag Kumar Vulisha 	return 0;
856*4a33bea0SAnurag Kumar Vulisha }
857*4a33bea0SAnurag Kumar Vulisha #endif /* CONFIG_PM */
858*4a33bea0SAnurag Kumar Vulisha 
859*4a33bea0SAnurag Kumar Vulisha static const struct dev_pm_ops xpsgtr_pm_ops = {
860*4a33bea0SAnurag Kumar Vulisha 	SET_SYSTEM_SLEEP_PM_OPS(xpsgtr_suspend, xpsgtr_resume)
861*4a33bea0SAnurag Kumar Vulisha };
862*4a33bea0SAnurag Kumar Vulisha 
863*4a33bea0SAnurag Kumar Vulisha /*
864*4a33bea0SAnurag Kumar Vulisha  * Probe & Platform Driver
865*4a33bea0SAnurag Kumar Vulisha  */
866*4a33bea0SAnurag Kumar Vulisha 
867*4a33bea0SAnurag Kumar Vulisha static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev)
868*4a33bea0SAnurag Kumar Vulisha {
869*4a33bea0SAnurag Kumar Vulisha 	unsigned int refclk;
870*4a33bea0SAnurag Kumar Vulisha 
871*4a33bea0SAnurag Kumar Vulisha 	for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->refclk_sscs); ++refclk) {
872*4a33bea0SAnurag Kumar Vulisha 		unsigned long rate;
873*4a33bea0SAnurag Kumar Vulisha 		unsigned int i;
874*4a33bea0SAnurag Kumar Vulisha 		struct clk *clk;
875*4a33bea0SAnurag Kumar Vulisha 		char name[8];
876*4a33bea0SAnurag Kumar Vulisha 
877*4a33bea0SAnurag Kumar Vulisha 		snprintf(name, sizeof(name), "ref%u", refclk);
878*4a33bea0SAnurag Kumar Vulisha 		clk = devm_clk_get_optional(gtr_dev->dev, name);
879*4a33bea0SAnurag Kumar Vulisha 		if (IS_ERR(clk)) {
880*4a33bea0SAnurag Kumar Vulisha 			if (PTR_ERR(clk) != -EPROBE_DEFER)
881*4a33bea0SAnurag Kumar Vulisha 				dev_err(gtr_dev->dev,
882*4a33bea0SAnurag Kumar Vulisha 					"Failed to get reference clock %u: %ld\n",
883*4a33bea0SAnurag Kumar Vulisha 					refclk, PTR_ERR(clk));
884*4a33bea0SAnurag Kumar Vulisha 			return PTR_ERR(clk);
885*4a33bea0SAnurag Kumar Vulisha 		}
886*4a33bea0SAnurag Kumar Vulisha 
887*4a33bea0SAnurag Kumar Vulisha 		if (!clk)
888*4a33bea0SAnurag Kumar Vulisha 			continue;
889*4a33bea0SAnurag Kumar Vulisha 
890*4a33bea0SAnurag Kumar Vulisha 		/*
891*4a33bea0SAnurag Kumar Vulisha 		 * Get the spread spectrum (SSC) settings for the reference
892*4a33bea0SAnurag Kumar Vulisha 		 * clock rate.
893*4a33bea0SAnurag Kumar Vulisha 		 */
894*4a33bea0SAnurag Kumar Vulisha 		rate = clk_get_rate(clk);
895*4a33bea0SAnurag Kumar Vulisha 
896*4a33bea0SAnurag Kumar Vulisha 		for (i = 0 ; i < ARRAY_SIZE(ssc_lookup); i++) {
897*4a33bea0SAnurag Kumar Vulisha 			if (rate == ssc_lookup[i].refclk_rate) {
898*4a33bea0SAnurag Kumar Vulisha 				gtr_dev->refclk_sscs[refclk] = &ssc_lookup[i];
899*4a33bea0SAnurag Kumar Vulisha 				break;
900*4a33bea0SAnurag Kumar Vulisha 			}
901*4a33bea0SAnurag Kumar Vulisha 		}
902*4a33bea0SAnurag Kumar Vulisha 
903*4a33bea0SAnurag Kumar Vulisha 		if (i == ARRAY_SIZE(ssc_lookup)) {
904*4a33bea0SAnurag Kumar Vulisha 			dev_err(gtr_dev->dev,
905*4a33bea0SAnurag Kumar Vulisha 				"Invalid rate %lu for reference clock %u\n",
906*4a33bea0SAnurag Kumar Vulisha 				rate, refclk);
907*4a33bea0SAnurag Kumar Vulisha 			return -EINVAL;
908*4a33bea0SAnurag Kumar Vulisha 		}
909*4a33bea0SAnurag Kumar Vulisha 	}
910*4a33bea0SAnurag Kumar Vulisha 
911*4a33bea0SAnurag Kumar Vulisha 	return 0;
912*4a33bea0SAnurag Kumar Vulisha }
913*4a33bea0SAnurag Kumar Vulisha 
914*4a33bea0SAnurag Kumar Vulisha static int xpsgtr_probe(struct platform_device *pdev)
915*4a33bea0SAnurag Kumar Vulisha {
916*4a33bea0SAnurag Kumar Vulisha 	struct device_node *np = pdev->dev.of_node;
917*4a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev;
918*4a33bea0SAnurag Kumar Vulisha 	struct phy_provider *provider;
919*4a33bea0SAnurag Kumar Vulisha 	unsigned int port;
920*4a33bea0SAnurag Kumar Vulisha 	int ret;
921*4a33bea0SAnurag Kumar Vulisha 
922*4a33bea0SAnurag Kumar Vulisha 	gtr_dev = devm_kzalloc(&pdev->dev, sizeof(*gtr_dev), GFP_KERNEL);
923*4a33bea0SAnurag Kumar Vulisha 	if (!gtr_dev)
924*4a33bea0SAnurag Kumar Vulisha 		return -ENOMEM;
925*4a33bea0SAnurag Kumar Vulisha 
926*4a33bea0SAnurag Kumar Vulisha 	gtr_dev->dev = &pdev->dev;
927*4a33bea0SAnurag Kumar Vulisha 	platform_set_drvdata(pdev, gtr_dev);
928*4a33bea0SAnurag Kumar Vulisha 
929*4a33bea0SAnurag Kumar Vulisha 	mutex_init(&gtr_dev->gtr_mutex);
930*4a33bea0SAnurag Kumar Vulisha 
931*4a33bea0SAnurag Kumar Vulisha 	if (of_device_is_compatible(np, "xlnx,zynqmp-psgtr"))
932*4a33bea0SAnurag Kumar Vulisha 		gtr_dev->tx_term_fix =
933*4a33bea0SAnurag Kumar Vulisha 			of_property_read_bool(np, "xlnx,tx-termination-fix");
934*4a33bea0SAnurag Kumar Vulisha 
935*4a33bea0SAnurag Kumar Vulisha 	/* Acquire resources. */
936*4a33bea0SAnurag Kumar Vulisha 	gtr_dev->serdes = devm_platform_ioremap_resource_byname(pdev, "serdes");
937*4a33bea0SAnurag Kumar Vulisha 	if (IS_ERR(gtr_dev->serdes))
938*4a33bea0SAnurag Kumar Vulisha 		return PTR_ERR(gtr_dev->serdes);
939*4a33bea0SAnurag Kumar Vulisha 
940*4a33bea0SAnurag Kumar Vulisha 	gtr_dev->siou = devm_platform_ioremap_resource_byname(pdev, "siou");
941*4a33bea0SAnurag Kumar Vulisha 	if (IS_ERR(gtr_dev->siou))
942*4a33bea0SAnurag Kumar Vulisha 		return PTR_ERR(gtr_dev->siou);
943*4a33bea0SAnurag Kumar Vulisha 
944*4a33bea0SAnurag Kumar Vulisha 	ret = xpsgtr_get_ref_clocks(gtr_dev);
945*4a33bea0SAnurag Kumar Vulisha 	if (ret)
946*4a33bea0SAnurag Kumar Vulisha 		return ret;
947*4a33bea0SAnurag Kumar Vulisha 
948*4a33bea0SAnurag Kumar Vulisha 	/* Create PHYs. */
949*4a33bea0SAnurag Kumar Vulisha 	for (port = 0; port < ARRAY_SIZE(gtr_dev->phys); ++port) {
950*4a33bea0SAnurag Kumar Vulisha 		struct xpsgtr_phy *gtr_phy = &gtr_dev->phys[port];
951*4a33bea0SAnurag Kumar Vulisha 		struct phy *phy;
952*4a33bea0SAnurag Kumar Vulisha 
953*4a33bea0SAnurag Kumar Vulisha 		gtr_phy->lane = port;
954*4a33bea0SAnurag Kumar Vulisha 		gtr_phy->dev = gtr_dev;
955*4a33bea0SAnurag Kumar Vulisha 
956*4a33bea0SAnurag Kumar Vulisha 		phy = devm_phy_create(&pdev->dev, np, &xpsgtr_phyops);
957*4a33bea0SAnurag Kumar Vulisha 		if (IS_ERR(phy)) {
958*4a33bea0SAnurag Kumar Vulisha 			dev_err(&pdev->dev, "failed to create PHY\n");
959*4a33bea0SAnurag Kumar Vulisha 			return PTR_ERR(phy);
960*4a33bea0SAnurag Kumar Vulisha 		}
961*4a33bea0SAnurag Kumar Vulisha 
962*4a33bea0SAnurag Kumar Vulisha 		gtr_phy->phy = phy;
963*4a33bea0SAnurag Kumar Vulisha 		phy_set_drvdata(phy, gtr_phy);
964*4a33bea0SAnurag Kumar Vulisha 	}
965*4a33bea0SAnurag Kumar Vulisha 
966*4a33bea0SAnurag Kumar Vulisha 	/* Register the PHY provider. */
967*4a33bea0SAnurag Kumar Vulisha 	provider = devm_of_phy_provider_register(&pdev->dev, xpsgtr_xlate);
968*4a33bea0SAnurag Kumar Vulisha 	if (IS_ERR(provider)) {
969*4a33bea0SAnurag Kumar Vulisha 		dev_err(&pdev->dev, "registering provider failed\n");
970*4a33bea0SAnurag Kumar Vulisha 		return PTR_ERR(provider);
971*4a33bea0SAnurag Kumar Vulisha 	}
972*4a33bea0SAnurag Kumar Vulisha 	return 0;
973*4a33bea0SAnurag Kumar Vulisha }
974*4a33bea0SAnurag Kumar Vulisha 
975*4a33bea0SAnurag Kumar Vulisha static const struct of_device_id xpsgtr_of_match[] = {
976*4a33bea0SAnurag Kumar Vulisha 	{ .compatible = "xlnx,zynqmp-psgtr", },
977*4a33bea0SAnurag Kumar Vulisha 	{ .compatible = "xlnx,zynqmp-psgtr-v1.1", },
978*4a33bea0SAnurag Kumar Vulisha 	{},
979*4a33bea0SAnurag Kumar Vulisha };
980*4a33bea0SAnurag Kumar Vulisha MODULE_DEVICE_TABLE(of, xpsgtr_of_match);
981*4a33bea0SAnurag Kumar Vulisha 
982*4a33bea0SAnurag Kumar Vulisha static struct platform_driver xpsgtr_driver = {
983*4a33bea0SAnurag Kumar Vulisha 	.probe = xpsgtr_probe,
984*4a33bea0SAnurag Kumar Vulisha 	.driver = {
985*4a33bea0SAnurag Kumar Vulisha 		.name = "xilinx-psgtr",
986*4a33bea0SAnurag Kumar Vulisha 		.of_match_table	= xpsgtr_of_match,
987*4a33bea0SAnurag Kumar Vulisha 		.pm =  &xpsgtr_pm_ops,
988*4a33bea0SAnurag Kumar Vulisha 	},
989*4a33bea0SAnurag Kumar Vulisha };
990*4a33bea0SAnurag Kumar Vulisha 
991*4a33bea0SAnurag Kumar Vulisha module_platform_driver(xpsgtr_driver);
992*4a33bea0SAnurag Kumar Vulisha 
993*4a33bea0SAnurag Kumar Vulisha MODULE_AUTHOR("Xilinx Inc.");
994*4a33bea0SAnurag Kumar Vulisha MODULE_LICENSE("GPL v2");
995*4a33bea0SAnurag Kumar Vulisha MODULE_DESCRIPTION("Xilinx ZynqMP High speed Gigabit Transceiver");
996