xref: /linux/drivers/phy/xilinx/phy-zynqmp.c (revision 32fafaf2ab185d26337f79d3ae558b4cb2b4a5d4)
14a33bea0SAnurag Kumar Vulisha // SPDX-License-Identifier: GPL-2.0
24a33bea0SAnurag Kumar Vulisha /*
34a33bea0SAnurag Kumar Vulisha  * phy-zynqmp.c - PHY driver for Xilinx ZynqMP GT.
44a33bea0SAnurag Kumar Vulisha  *
54a33bea0SAnurag Kumar Vulisha  * Copyright (C) 2018-2020 Xilinx Inc.
64a33bea0SAnurag Kumar Vulisha  *
74a33bea0SAnurag Kumar Vulisha  * Author: Anurag Kumar Vulisha <anuragku@xilinx.com>
84a33bea0SAnurag Kumar Vulisha  * Author: Subbaraya Sundeep <sundeep.lkml@gmail.com>
94a33bea0SAnurag Kumar Vulisha  * Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
104a33bea0SAnurag Kumar Vulisha  *
11c8481d99SRadhey Shyam Pandey  * This driver is tested for USB, SGMII, SATA and Display Port currently.
12c8481d99SRadhey Shyam Pandey  * PCIe should also work but that is experimental as of now.
134a33bea0SAnurag Kumar Vulisha  */
144a33bea0SAnurag Kumar Vulisha 
154a33bea0SAnurag Kumar Vulisha #include <linux/clk.h>
1604490b62SSean Anderson #include <linux/debugfs.h>
174a33bea0SAnurag Kumar Vulisha #include <linux/delay.h>
184a33bea0SAnurag Kumar Vulisha #include <linux/io.h>
194a33bea0SAnurag Kumar Vulisha #include <linux/kernel.h>
204a33bea0SAnurag Kumar Vulisha #include <linux/module.h>
214a33bea0SAnurag Kumar Vulisha #include <linux/of.h>
224a33bea0SAnurag Kumar Vulisha #include <linux/phy/phy.h>
234a33bea0SAnurag Kumar Vulisha #include <linux/platform_device.h>
24b3db66f6SPiyush Mehta #include <linux/pm_runtime.h>
254a33bea0SAnurag Kumar Vulisha #include <linux/slab.h>
264a33bea0SAnurag Kumar Vulisha 
274a33bea0SAnurag Kumar Vulisha #include <dt-bindings/phy/phy.h>
284a33bea0SAnurag Kumar Vulisha 
294a33bea0SAnurag Kumar Vulisha /*
304a33bea0SAnurag Kumar Vulisha  * Lane Registers
314a33bea0SAnurag Kumar Vulisha  */
324a33bea0SAnurag Kumar Vulisha 
334a33bea0SAnurag Kumar Vulisha /* TX De-emphasis parameters */
344a33bea0SAnurag Kumar Vulisha #define L0_TX_ANA_TM_18			0x0048
354a33bea0SAnurag Kumar Vulisha #define L0_TX_ANA_TM_118		0x01d8
364a33bea0SAnurag Kumar Vulisha #define L0_TX_ANA_TM_118_FORCE_17_0	BIT(0)
374a33bea0SAnurag Kumar Vulisha 
384a33bea0SAnurag Kumar Vulisha /* DN Resistor calibration code parameters */
394a33bea0SAnurag Kumar Vulisha #define L0_TXPMA_ST_3			0x0b0c
404a33bea0SAnurag Kumar Vulisha #define L0_DN_CALIB_CODE		0x3f
414a33bea0SAnurag Kumar Vulisha 
424a33bea0SAnurag Kumar Vulisha /* PMA control parameters */
434a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45			0x0cb4
444a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_48			0x0cc0
454a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_OVER_DP_MAIN	BIT(0)
464a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_ENABLE_DP_MAIN	BIT(1)
474a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_OVER_DP_POST1	BIT(2)
484a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_ENABLE_DP_POST1	BIT(3)
494a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_OVER_DP_POST2	BIT(4)
504a33bea0SAnurag Kumar Vulisha #define L0_TXPMD_TM_45_ENABLE_DP_POST2	BIT(5)
514a33bea0SAnurag Kumar Vulisha 
524a33bea0SAnurag Kumar Vulisha /* PCS control parameters */
534a33bea0SAnurag Kumar Vulisha #define L0_TM_DIG_6			0x106c
544a33bea0SAnurag Kumar Vulisha #define L0_TM_DIS_DESCRAMBLE_DECODER	0x0f
554a33bea0SAnurag Kumar Vulisha #define L0_TX_DIG_61			0x00f4
564a33bea0SAnurag Kumar Vulisha #define L0_TM_DISABLE_SCRAMBLE_ENCODER	0x0f
574a33bea0SAnurag Kumar Vulisha 
584a33bea0SAnurag Kumar Vulisha /* PLL Test Mode register parameters */
594a33bea0SAnurag Kumar Vulisha #define L0_TM_PLL_DIG_37		0x2094
604a33bea0SAnurag Kumar Vulisha #define L0_TM_COARSE_CODE_LIMIT		0x10
614a33bea0SAnurag Kumar Vulisha 
624a33bea0SAnurag Kumar Vulisha /* PLL SSC step size offsets */
634a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEPS_0_LSB		0x2368
644a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEPS_1_MSB		0x236c
654a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEP_SIZE_0_LSB	0x2370
664a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEP_SIZE_1		0x2374
674a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEP_SIZE_2		0x2378
684a33bea0SAnurag Kumar Vulisha #define L0_PLL_SS_STEP_SIZE_3_MSB	0x237c
694a33bea0SAnurag Kumar Vulisha #define L0_PLL_STATUS_READ_1		0x23e4
704a33bea0SAnurag Kumar Vulisha 
714a33bea0SAnurag Kumar Vulisha /* SSC step size parameters */
724a33bea0SAnurag Kumar Vulisha #define STEP_SIZE_0_MASK		0xff
734a33bea0SAnurag Kumar Vulisha #define STEP_SIZE_1_MASK		0xff
744a33bea0SAnurag Kumar Vulisha #define STEP_SIZE_2_MASK		0xff
754a33bea0SAnurag Kumar Vulisha #define STEP_SIZE_3_MASK		0x3
764a33bea0SAnurag Kumar Vulisha #define STEP_SIZE_SHIFT			8
774a33bea0SAnurag Kumar Vulisha #define FORCE_STEP_SIZE			0x10
784a33bea0SAnurag Kumar Vulisha #define FORCE_STEPS			0x20
794a33bea0SAnurag Kumar Vulisha #define STEPS_0_MASK			0xff
804a33bea0SAnurag Kumar Vulisha #define STEPS_1_MASK			0x07
814a33bea0SAnurag Kumar Vulisha 
824a33bea0SAnurag Kumar Vulisha /* Reference clock selection parameters */
834a33bea0SAnurag Kumar Vulisha #define L0_Ln_REF_CLK_SEL(n)		(0x2860 + (n) * 4)
84687d6bccSSean Anderson #define L0_REF_CLK_LCL_SEL		BIT(7)
85687d6bccSSean Anderson #define L0_REF_CLK_SEL_MASK		0x9f
864a33bea0SAnurag Kumar Vulisha 
874a33bea0SAnurag Kumar Vulisha /* Calibration digital logic parameters */
884a33bea0SAnurag Kumar Vulisha #define L3_TM_CALIB_DIG19		0xec4c
894a33bea0SAnurag Kumar Vulisha #define L3_CALIB_DONE_STATUS		0xef14
904a33bea0SAnurag Kumar Vulisha #define L3_TM_CALIB_DIG18		0xec48
914a33bea0SAnurag Kumar Vulisha #define L3_TM_CALIB_DIG19_NSW		0x07
924a33bea0SAnurag Kumar Vulisha #define L3_TM_CALIB_DIG18_NSW		0xe0
934a33bea0SAnurag Kumar Vulisha #define L3_TM_OVERRIDE_NSW_CODE         0x20
944a33bea0SAnurag Kumar Vulisha #define L3_CALIB_DONE			0x02
954a33bea0SAnurag Kumar Vulisha #define L3_NSW_SHIFT			5
964a33bea0SAnurag Kumar Vulisha #define L3_NSW_PIPE_SHIFT		4
974a33bea0SAnurag Kumar Vulisha #define L3_NSW_CALIB_SHIFT		3
984a33bea0SAnurag Kumar Vulisha 
994a33bea0SAnurag Kumar Vulisha #define PHY_REG_OFFSET			0x4000
1004a33bea0SAnurag Kumar Vulisha 
1014a33bea0SAnurag Kumar Vulisha /*
1024a33bea0SAnurag Kumar Vulisha  * Global Registers
1034a33bea0SAnurag Kumar Vulisha  */
1044a33bea0SAnurag Kumar Vulisha 
1054a33bea0SAnurag Kumar Vulisha /* Refclk selection parameters */
1064a33bea0SAnurag Kumar Vulisha #define PLL_REF_SEL(n)			(0x10000 + (n) * 4)
1074a33bea0SAnurag Kumar Vulisha #define PLL_FREQ_MASK			0x1f
1084a33bea0SAnurag Kumar Vulisha #define PLL_STATUS_LOCKED		0x10
1094a33bea0SAnurag Kumar Vulisha 
1104a33bea0SAnurag Kumar Vulisha /* Inter Connect Matrix parameters */
1114a33bea0SAnurag Kumar Vulisha #define ICM_CFG0			0x10010
1124a33bea0SAnurag Kumar Vulisha #define ICM_CFG1			0x10014
1134a33bea0SAnurag Kumar Vulisha #define ICM_CFG0_L0_MASK		0x07
1144a33bea0SAnurag Kumar Vulisha #define ICM_CFG0_L1_MASK		0x70
1154a33bea0SAnurag Kumar Vulisha #define ICM_CFG1_L2_MASK		0x07
1164a33bea0SAnurag Kumar Vulisha #define ICM_CFG2_L3_MASK		0x70
1174a33bea0SAnurag Kumar Vulisha #define ICM_CFG_SHIFT			4
1184a33bea0SAnurag Kumar Vulisha 
1194a33bea0SAnurag Kumar Vulisha /* Inter Connect Matrix allowed protocols */
1204a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_PD			0x0
1214a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_PCIE		0x1
1224a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_SATA		0x2
1234a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_USB		0x3
1244a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_DP			0x4
1254a33bea0SAnurag Kumar Vulisha #define ICM_PROTOCOL_SGMII		0x5
1264a33bea0SAnurag Kumar Vulisha 
12704490b62SSean Anderson static const char *const xpsgtr_icm_str[] = {
12804490b62SSean Anderson 	[ICM_PROTOCOL_PD] = "none",
12904490b62SSean Anderson 	[ICM_PROTOCOL_PCIE] = "PCIe",
13004490b62SSean Anderson 	[ICM_PROTOCOL_SATA] = "SATA",
13104490b62SSean Anderson 	[ICM_PROTOCOL_USB] = "USB",
13204490b62SSean Anderson 	[ICM_PROTOCOL_DP] = "DisplayPort",
13304490b62SSean Anderson 	[ICM_PROTOCOL_SGMII] = "SGMII",
13404490b62SSean Anderson };
13504490b62SSean Anderson 
1364a33bea0SAnurag Kumar Vulisha /* Test Mode common reset control  parameters */
1374a33bea0SAnurag Kumar Vulisha #define TM_CMN_RST			0x10018
1384a33bea0SAnurag Kumar Vulisha #define TM_CMN_RST_EN			0x1
1394a33bea0SAnurag Kumar Vulisha #define TM_CMN_RST_SET			0x2
1404a33bea0SAnurag Kumar Vulisha #define TM_CMN_RST_MASK			0x3
1414a33bea0SAnurag Kumar Vulisha 
1424a33bea0SAnurag Kumar Vulisha /* Bus width parameters */
1434a33bea0SAnurag Kumar Vulisha #define TX_PROT_BUS_WIDTH		0x10040
1444a33bea0SAnurag Kumar Vulisha #define RX_PROT_BUS_WIDTH		0x10044
1454a33bea0SAnurag Kumar Vulisha #define PROT_BUS_WIDTH_10		0x0
1464a33bea0SAnurag Kumar Vulisha #define PROT_BUS_WIDTH_20		0x1
1474a33bea0SAnurag Kumar Vulisha #define PROT_BUS_WIDTH_40		0x2
14837291f60SRobert Hancock #define PROT_BUS_WIDTH_SHIFT(n)		((n) * 2)
14937291f60SRobert Hancock #define PROT_BUS_WIDTH_MASK(n)		GENMASK((n) * 2 + 1, (n) * 2)
1504a33bea0SAnurag Kumar Vulisha 
1514a33bea0SAnurag Kumar Vulisha /* Number of GT lanes */
1524a33bea0SAnurag Kumar Vulisha #define NUM_LANES			4
1534a33bea0SAnurag Kumar Vulisha 
1544a33bea0SAnurag Kumar Vulisha /* SIOU SATA control register */
1554a33bea0SAnurag Kumar Vulisha #define SATA_CONTROL_OFFSET		0x0100
1564a33bea0SAnurag Kumar Vulisha 
1574a33bea0SAnurag Kumar Vulisha /* Total number of controllers */
1584a33bea0SAnurag Kumar Vulisha #define CONTROLLERS_PER_LANE		5
1594a33bea0SAnurag Kumar Vulisha 
1604a33bea0SAnurag Kumar Vulisha /* Timeout values */
1614a33bea0SAnurag Kumar Vulisha #define TIMEOUT_US			1000
1624a33bea0SAnurag Kumar Vulisha 
163*5af9b304SPiyush Mehta /* Lane 0/1/2/3 offset */
164*5af9b304SPiyush Mehta #define DIG_8(n)		((0x4000 * (n)) + 0x1074)
165*5af9b304SPiyush Mehta #define ILL13(n)		((0x4000 * (n)) + 0x1994)
166*5af9b304SPiyush Mehta #define DIG_10(n)		((0x4000 * (n)) + 0x107c)
167*5af9b304SPiyush Mehta #define RST_DLY(n)		((0x4000 * (n)) + 0x19a4)
168*5af9b304SPiyush Mehta #define BYP_15(n)		((0x4000 * (n)) + 0x1038)
169*5af9b304SPiyush Mehta #define BYP_12(n)		((0x4000 * (n)) + 0x102c)
170*5af9b304SPiyush Mehta #define MISC3(n)		((0x4000 * (n)) + 0x19ac)
171*5af9b304SPiyush Mehta #define EQ11(n)			((0x4000 * (n)) + 0x1978)
172*5af9b304SPiyush Mehta 
173*5af9b304SPiyush Mehta static u32 save_reg_address[] = {
174*5af9b304SPiyush Mehta 	/* Lane 0/1/2/3 Register */
175*5af9b304SPiyush Mehta 	DIG_8(0), ILL13(0), DIG_10(0), RST_DLY(0), BYP_15(0), BYP_12(0), MISC3(0), EQ11(0),
176*5af9b304SPiyush Mehta 	DIG_8(1), ILL13(1), DIG_10(1), RST_DLY(1), BYP_15(1), BYP_12(1), MISC3(1), EQ11(1),
177*5af9b304SPiyush Mehta 	DIG_8(2), ILL13(2), DIG_10(2), RST_DLY(2), BYP_15(2), BYP_12(2), MISC3(2), EQ11(2),
178*5af9b304SPiyush Mehta 	DIG_8(3), ILL13(3), DIG_10(3), RST_DLY(3), BYP_15(3), BYP_12(3), MISC3(3), EQ11(3),
179*5af9b304SPiyush Mehta };
180*5af9b304SPiyush Mehta 
1814a33bea0SAnurag Kumar Vulisha struct xpsgtr_dev;
1824a33bea0SAnurag Kumar Vulisha 
1834a33bea0SAnurag Kumar Vulisha /**
1844a33bea0SAnurag Kumar Vulisha  * struct xpsgtr_ssc - structure to hold SSC settings for a lane
1854a33bea0SAnurag Kumar Vulisha  * @refclk_rate: PLL reference clock frequency
1864a33bea0SAnurag Kumar Vulisha  * @pll_ref_clk: value to be written to register for corresponding ref clk rate
1874a33bea0SAnurag Kumar Vulisha  * @steps: number of steps of SSC (Spread Spectrum Clock)
1884a33bea0SAnurag Kumar Vulisha  * @step_size: step size of each step
1894a33bea0SAnurag Kumar Vulisha  */
1904a33bea0SAnurag Kumar Vulisha struct xpsgtr_ssc {
1914a33bea0SAnurag Kumar Vulisha 	u32 refclk_rate;
1924a33bea0SAnurag Kumar Vulisha 	u8  pll_ref_clk;
1934a33bea0SAnurag Kumar Vulisha 	u32 steps;
1944a33bea0SAnurag Kumar Vulisha 	u32 step_size;
1954a33bea0SAnurag Kumar Vulisha };
1964a33bea0SAnurag Kumar Vulisha 
1974a33bea0SAnurag Kumar Vulisha /**
1984a33bea0SAnurag Kumar Vulisha  * struct xpsgtr_phy - representation of a lane
1994a33bea0SAnurag Kumar Vulisha  * @phy: pointer to the kernel PHY device
2006959d236SSean Anderson  * @instance: instance of the protocol type (such as the lane within a
2016959d236SSean Anderson  *            protocol, or the USB/Ethernet controller)
2024a33bea0SAnurag Kumar Vulisha  * @lane: lane number
2034a33bea0SAnurag Kumar Vulisha  * @protocol: protocol in which the lane operates
2044a33bea0SAnurag Kumar Vulisha  * @skip_phy_init: skip phy_init() if true
2054a33bea0SAnurag Kumar Vulisha  * @dev: pointer to the xpsgtr_dev instance
2064a33bea0SAnurag Kumar Vulisha  * @refclk: reference clock index
2074a33bea0SAnurag Kumar Vulisha  */
2084a33bea0SAnurag Kumar Vulisha struct xpsgtr_phy {
2094a33bea0SAnurag Kumar Vulisha 	struct phy *phy;
2106959d236SSean Anderson 	u8 instance;
2114a33bea0SAnurag Kumar Vulisha 	u8 lane;
2124a33bea0SAnurag Kumar Vulisha 	u8 protocol;
2134a33bea0SAnurag Kumar Vulisha 	bool skip_phy_init;
2144a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *dev;
2154a33bea0SAnurag Kumar Vulisha 	unsigned int refclk;
2164a33bea0SAnurag Kumar Vulisha };
2174a33bea0SAnurag Kumar Vulisha 
2184a33bea0SAnurag Kumar Vulisha /**
2194a33bea0SAnurag Kumar Vulisha  * struct xpsgtr_dev - representation of a ZynMP GT device
2204a33bea0SAnurag Kumar Vulisha  * @dev: pointer to device
2214a33bea0SAnurag Kumar Vulisha  * @serdes: serdes base address
2224a33bea0SAnurag Kumar Vulisha  * @siou: siou base address
2234a33bea0SAnurag Kumar Vulisha  * @gtr_mutex: mutex for locking
2244a33bea0SAnurag Kumar Vulisha  * @phys: PHY lanes
2254a33bea0SAnurag Kumar Vulisha  * @refclk_sscs: spread spectrum settings for the reference clocks
22667097754SManish Narani  * @clk: reference clocks
2274a33bea0SAnurag Kumar Vulisha  * @tx_term_fix: fix for GT issue
2284a33bea0SAnurag Kumar Vulisha  * @saved_icm_cfg0: stored value of ICM CFG0 register
2294a33bea0SAnurag Kumar Vulisha  * @saved_icm_cfg1: stored value of ICM CFG1 register
230*5af9b304SPiyush Mehta  * @saved_regs: registers to be saved/restored during suspend/resume
2314a33bea0SAnurag Kumar Vulisha  */
2324a33bea0SAnurag Kumar Vulisha struct xpsgtr_dev {
2334a33bea0SAnurag Kumar Vulisha 	struct device *dev;
2344a33bea0SAnurag Kumar Vulisha 	void __iomem *serdes;
2354a33bea0SAnurag Kumar Vulisha 	void __iomem *siou;
2364a33bea0SAnurag Kumar Vulisha 	struct mutex gtr_mutex; /* mutex for locking */
2374a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy phys[NUM_LANES];
2384a33bea0SAnurag Kumar Vulisha 	const struct xpsgtr_ssc *refclk_sscs[NUM_LANES];
23967097754SManish Narani 	struct clk *clk[NUM_LANES];
2404a33bea0SAnurag Kumar Vulisha 	bool tx_term_fix;
2414a33bea0SAnurag Kumar Vulisha 	unsigned int saved_icm_cfg0;
2424a33bea0SAnurag Kumar Vulisha 	unsigned int saved_icm_cfg1;
243*5af9b304SPiyush Mehta 	u32 *saved_regs;
2444a33bea0SAnurag Kumar Vulisha };
2454a33bea0SAnurag Kumar Vulisha 
2464a33bea0SAnurag Kumar Vulisha /*
2474a33bea0SAnurag Kumar Vulisha  * Configuration Data
2484a33bea0SAnurag Kumar Vulisha  */
2494a33bea0SAnurag Kumar Vulisha 
2504a33bea0SAnurag Kumar Vulisha /* lookup table to hold all settings needed for a ref clock frequency */
2514a33bea0SAnurag Kumar Vulisha static const struct xpsgtr_ssc ssc_lookup[] = {
2524a33bea0SAnurag Kumar Vulisha 	{  19200000, 0x05,  608, 264020 },
2534a33bea0SAnurag Kumar Vulisha 	{  20000000, 0x06,  634, 243454 },
2544a33bea0SAnurag Kumar Vulisha 	{  24000000, 0x07,  760, 168973 },
2554a33bea0SAnurag Kumar Vulisha 	{  26000000, 0x08,  824, 143860 },
2564a33bea0SAnurag Kumar Vulisha 	{  27000000, 0x09,  856,  86551 },
2574a33bea0SAnurag Kumar Vulisha 	{  38400000, 0x0a, 1218,  65896 },
2584a33bea0SAnurag Kumar Vulisha 	{  40000000, 0x0b,  634, 243454 },
2594a33bea0SAnurag Kumar Vulisha 	{  52000000, 0x0c,  824, 143860 },
2604a33bea0SAnurag Kumar Vulisha 	{ 100000000, 0x0d, 1058,  87533 },
2614a33bea0SAnurag Kumar Vulisha 	{ 108000000, 0x0e,  856,  86551 },
2624a33bea0SAnurag Kumar Vulisha 	{ 125000000, 0x0f,  992, 119497 },
2634a33bea0SAnurag Kumar Vulisha 	{ 135000000, 0x10, 1070,  55393 },
2644a33bea0SAnurag Kumar Vulisha 	{ 150000000, 0x11,  792, 187091 }
2654a33bea0SAnurag Kumar Vulisha };
2664a33bea0SAnurag Kumar Vulisha 
2674a33bea0SAnurag Kumar Vulisha /*
2684a33bea0SAnurag Kumar Vulisha  * I/O Accessors
2694a33bea0SAnurag Kumar Vulisha  */
2704a33bea0SAnurag Kumar Vulisha 
xpsgtr_read(struct xpsgtr_dev * gtr_dev,u32 reg)2714a33bea0SAnurag Kumar Vulisha static inline u32 xpsgtr_read(struct xpsgtr_dev *gtr_dev, u32 reg)
2724a33bea0SAnurag Kumar Vulisha {
2734a33bea0SAnurag Kumar Vulisha 	return readl(gtr_dev->serdes + reg);
2744a33bea0SAnurag Kumar Vulisha }
2754a33bea0SAnurag Kumar Vulisha 
xpsgtr_write(struct xpsgtr_dev * gtr_dev,u32 reg,u32 value)2764a33bea0SAnurag Kumar Vulisha static inline void xpsgtr_write(struct xpsgtr_dev *gtr_dev, u32 reg, u32 value)
2774a33bea0SAnurag Kumar Vulisha {
2784a33bea0SAnurag Kumar Vulisha 	writel(value, gtr_dev->serdes + reg);
2794a33bea0SAnurag Kumar Vulisha }
2804a33bea0SAnurag Kumar Vulisha 
xpsgtr_clr_set(struct xpsgtr_dev * gtr_dev,u32 reg,u32 clr,u32 set)2814a33bea0SAnurag Kumar Vulisha static inline void xpsgtr_clr_set(struct xpsgtr_dev *gtr_dev, u32 reg,
2824a33bea0SAnurag Kumar Vulisha 				  u32 clr, u32 set)
2834a33bea0SAnurag Kumar Vulisha {
2844a33bea0SAnurag Kumar Vulisha 	u32 value = xpsgtr_read(gtr_dev, reg);
2854a33bea0SAnurag Kumar Vulisha 
2864a33bea0SAnurag Kumar Vulisha 	value &= ~clr;
2874a33bea0SAnurag Kumar Vulisha 	value |= set;
2884a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, reg, value);
2894a33bea0SAnurag Kumar Vulisha }
2904a33bea0SAnurag Kumar Vulisha 
xpsgtr_read_phy(struct xpsgtr_phy * gtr_phy,u32 reg)2914a33bea0SAnurag Kumar Vulisha static inline u32 xpsgtr_read_phy(struct xpsgtr_phy *gtr_phy, u32 reg)
2924a33bea0SAnurag Kumar Vulisha {
2934a33bea0SAnurag Kumar Vulisha 	void __iomem *addr = gtr_phy->dev->serdes
2944a33bea0SAnurag Kumar Vulisha 			   + gtr_phy->lane * PHY_REG_OFFSET + reg;
2954a33bea0SAnurag Kumar Vulisha 
2964a33bea0SAnurag Kumar Vulisha 	return readl(addr);
2974a33bea0SAnurag Kumar Vulisha }
2984a33bea0SAnurag Kumar Vulisha 
xpsgtr_write_phy(struct xpsgtr_phy * gtr_phy,u32 reg,u32 value)2994a33bea0SAnurag Kumar Vulisha static inline void xpsgtr_write_phy(struct xpsgtr_phy *gtr_phy,
3004a33bea0SAnurag Kumar Vulisha 				    u32 reg, u32 value)
3014a33bea0SAnurag Kumar Vulisha {
3024a33bea0SAnurag Kumar Vulisha 	void __iomem *addr = gtr_phy->dev->serdes
3034a33bea0SAnurag Kumar Vulisha 			   + gtr_phy->lane * PHY_REG_OFFSET + reg;
3044a33bea0SAnurag Kumar Vulisha 
3054a33bea0SAnurag Kumar Vulisha 	writel(value, addr);
3064a33bea0SAnurag Kumar Vulisha }
3074a33bea0SAnurag Kumar Vulisha 
xpsgtr_clr_set_phy(struct xpsgtr_phy * gtr_phy,u32 reg,u32 clr,u32 set)3084a33bea0SAnurag Kumar Vulisha static inline void xpsgtr_clr_set_phy(struct xpsgtr_phy *gtr_phy,
3094a33bea0SAnurag Kumar Vulisha 				      u32 reg, u32 clr, u32 set)
3104a33bea0SAnurag Kumar Vulisha {
3114a33bea0SAnurag Kumar Vulisha 	void __iomem *addr = gtr_phy->dev->serdes
3124a33bea0SAnurag Kumar Vulisha 			   + gtr_phy->lane * PHY_REG_OFFSET + reg;
3134a33bea0SAnurag Kumar Vulisha 
3144a33bea0SAnurag Kumar Vulisha 	writel((readl(addr) & ~clr) | set, addr);
3154a33bea0SAnurag Kumar Vulisha }
3164a33bea0SAnurag Kumar Vulisha 
317*5af9b304SPiyush Mehta /**
318*5af9b304SPiyush Mehta  * xpsgtr_save_lane_regs - Saves registers on suspend
319*5af9b304SPiyush Mehta  * @gtr_dev: pointer to phy controller context structure
320*5af9b304SPiyush Mehta  */
xpsgtr_save_lane_regs(struct xpsgtr_dev * gtr_dev)321*5af9b304SPiyush Mehta static void xpsgtr_save_lane_regs(struct xpsgtr_dev *gtr_dev)
322*5af9b304SPiyush Mehta {
323*5af9b304SPiyush Mehta 	int i;
324*5af9b304SPiyush Mehta 
325*5af9b304SPiyush Mehta 	for (i = 0; i < ARRAY_SIZE(save_reg_address); i++)
326*5af9b304SPiyush Mehta 		gtr_dev->saved_regs[i] = xpsgtr_read(gtr_dev,
327*5af9b304SPiyush Mehta 						     save_reg_address[i]);
328*5af9b304SPiyush Mehta }
329*5af9b304SPiyush Mehta 
330*5af9b304SPiyush Mehta /**
331*5af9b304SPiyush Mehta  * xpsgtr_restore_lane_regs - Restores registers on resume
332*5af9b304SPiyush Mehta  * @gtr_dev: pointer to phy controller context structure
333*5af9b304SPiyush Mehta  */
xpsgtr_restore_lane_regs(struct xpsgtr_dev * gtr_dev)334*5af9b304SPiyush Mehta static void xpsgtr_restore_lane_regs(struct xpsgtr_dev *gtr_dev)
335*5af9b304SPiyush Mehta {
336*5af9b304SPiyush Mehta 	int i;
337*5af9b304SPiyush Mehta 
338*5af9b304SPiyush Mehta 	for (i = 0; i < ARRAY_SIZE(save_reg_address); i++)
339*5af9b304SPiyush Mehta 		xpsgtr_write(gtr_dev, save_reg_address[i],
340*5af9b304SPiyush Mehta 			     gtr_dev->saved_regs[i]);
341*5af9b304SPiyush Mehta }
342*5af9b304SPiyush Mehta 
3434a33bea0SAnurag Kumar Vulisha /*
3444a33bea0SAnurag Kumar Vulisha  * Hardware Configuration
3454a33bea0SAnurag Kumar Vulisha  */
3464a33bea0SAnurag Kumar Vulisha 
3474a33bea0SAnurag Kumar Vulisha /* Wait for the PLL to lock (with a timeout). */
xpsgtr_wait_pll_lock(struct phy * phy)3484a33bea0SAnurag Kumar Vulisha static int xpsgtr_wait_pll_lock(struct phy *phy)
3494a33bea0SAnurag Kumar Vulisha {
3504a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
3514a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
3524a33bea0SAnurag Kumar Vulisha 	unsigned int timeout = TIMEOUT_US;
353235d8b66SSean Anderson 	u8 protocol = gtr_phy->protocol;
3544a33bea0SAnurag Kumar Vulisha 	int ret;
3554a33bea0SAnurag Kumar Vulisha 
3564a33bea0SAnurag Kumar Vulisha 	dev_dbg(gtr_dev->dev, "Waiting for PLL lock\n");
3574a33bea0SAnurag Kumar Vulisha 
358235d8b66SSean Anderson 	/*
359235d8b66SSean Anderson 	 * For DP and PCIe, only the instance 0 PLL is used. Switch to that phy
360235d8b66SSean Anderson 	 * so we wait on the right PLL.
361235d8b66SSean Anderson 	 */
362235d8b66SSean Anderson 	if ((protocol == ICM_PROTOCOL_DP || protocol == ICM_PROTOCOL_PCIE) &&
363235d8b66SSean Anderson 	    gtr_phy->instance) {
364235d8b66SSean Anderson 		int i;
365235d8b66SSean Anderson 
366235d8b66SSean Anderson 		for (i = 0; i < NUM_LANES; i++) {
367235d8b66SSean Anderson 			gtr_phy = &gtr_dev->phys[i];
368235d8b66SSean Anderson 
369235d8b66SSean Anderson 			if (gtr_phy->protocol == protocol && !gtr_phy->instance)
370235d8b66SSean Anderson 				goto got_phy;
371235d8b66SSean Anderson 		}
372235d8b66SSean Anderson 
373235d8b66SSean Anderson 		return -EBUSY;
374235d8b66SSean Anderson 	}
375235d8b66SSean Anderson 
376235d8b66SSean Anderson got_phy:
3774a33bea0SAnurag Kumar Vulisha 	while (1) {
3784a33bea0SAnurag Kumar Vulisha 		u32 reg = xpsgtr_read_phy(gtr_phy, L0_PLL_STATUS_READ_1);
3794a33bea0SAnurag Kumar Vulisha 
3804a33bea0SAnurag Kumar Vulisha 		if ((reg & PLL_STATUS_LOCKED) == PLL_STATUS_LOCKED) {
3814a33bea0SAnurag Kumar Vulisha 			ret = 0;
3824a33bea0SAnurag Kumar Vulisha 			break;
3834a33bea0SAnurag Kumar Vulisha 		}
3844a33bea0SAnurag Kumar Vulisha 
3854a33bea0SAnurag Kumar Vulisha 		if (--timeout == 0) {
3864a33bea0SAnurag Kumar Vulisha 			ret = -ETIMEDOUT;
3874a33bea0SAnurag Kumar Vulisha 			break;
3884a33bea0SAnurag Kumar Vulisha 		}
3894a33bea0SAnurag Kumar Vulisha 
3904a33bea0SAnurag Kumar Vulisha 		udelay(1);
3914a33bea0SAnurag Kumar Vulisha 	}
3924a33bea0SAnurag Kumar Vulisha 
3934a33bea0SAnurag Kumar Vulisha 	if (ret == -ETIMEDOUT)
3944a33bea0SAnurag Kumar Vulisha 		dev_err(gtr_dev->dev,
3956959d236SSean Anderson 			"lane %u (protocol %u, instance %u): PLL lock timeout\n",
3966959d236SSean Anderson 			gtr_phy->lane, gtr_phy->protocol, gtr_phy->instance);
3974a33bea0SAnurag Kumar Vulisha 
3984a33bea0SAnurag Kumar Vulisha 	return ret;
3994a33bea0SAnurag Kumar Vulisha }
4004a33bea0SAnurag Kumar Vulisha 
4014a33bea0SAnurag Kumar Vulisha /* Configure PLL and spread-sprectrum clock. */
xpsgtr_configure_pll(struct xpsgtr_phy * gtr_phy)4024a33bea0SAnurag Kumar Vulisha static void xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy)
4034a33bea0SAnurag Kumar Vulisha {
4044a33bea0SAnurag Kumar Vulisha 	const struct xpsgtr_ssc *ssc;
4054a33bea0SAnurag Kumar Vulisha 	u32 step_size;
4064a33bea0SAnurag Kumar Vulisha 
4074a33bea0SAnurag Kumar Vulisha 	ssc = gtr_phy->dev->refclk_sscs[gtr_phy->refclk];
4084a33bea0SAnurag Kumar Vulisha 	step_size = ssc->step_size;
4094a33bea0SAnurag Kumar Vulisha 
4104a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_phy->dev, PLL_REF_SEL(gtr_phy->lane),
4114a33bea0SAnurag Kumar Vulisha 		       PLL_FREQ_MASK, ssc->pll_ref_clk);
4124a33bea0SAnurag Kumar Vulisha 
4134a33bea0SAnurag Kumar Vulisha 	/* Enable lane clock sharing, if required */
414687d6bccSSean Anderson 	if (gtr_phy->refclk == gtr_phy->lane)
415687d6bccSSean Anderson 		xpsgtr_clr_set(gtr_phy->dev, L0_Ln_REF_CLK_SEL(gtr_phy->lane),
416687d6bccSSean Anderson 			       L0_REF_CLK_SEL_MASK, L0_REF_CLK_LCL_SEL);
417687d6bccSSean Anderson 	else
4184a33bea0SAnurag Kumar Vulisha 		xpsgtr_clr_set(gtr_phy->dev, L0_Ln_REF_CLK_SEL(gtr_phy->lane),
4194a33bea0SAnurag Kumar Vulisha 			       L0_REF_CLK_SEL_MASK, 1 << gtr_phy->refclk);
4204a33bea0SAnurag Kumar Vulisha 
4214a33bea0SAnurag Kumar Vulisha 	/* SSC step size [7:0] */
4224a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_0_LSB,
4234a33bea0SAnurag Kumar Vulisha 			   STEP_SIZE_0_MASK, step_size & STEP_SIZE_0_MASK);
4244a33bea0SAnurag Kumar Vulisha 
4254a33bea0SAnurag Kumar Vulisha 	/* SSC step size [15:8] */
4264a33bea0SAnurag Kumar Vulisha 	step_size >>= STEP_SIZE_SHIFT;
4274a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_1,
4284a33bea0SAnurag Kumar Vulisha 			   STEP_SIZE_1_MASK, step_size & STEP_SIZE_1_MASK);
4294a33bea0SAnurag Kumar Vulisha 
4304a33bea0SAnurag Kumar Vulisha 	/* SSC step size [23:16] */
4314a33bea0SAnurag Kumar Vulisha 	step_size >>= STEP_SIZE_SHIFT;
4324a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_2,
4334a33bea0SAnurag Kumar Vulisha 			   STEP_SIZE_2_MASK, step_size & STEP_SIZE_2_MASK);
4344a33bea0SAnurag Kumar Vulisha 
4354a33bea0SAnurag Kumar Vulisha 	/* SSC steps [7:0] */
4364a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEPS_0_LSB,
4374a33bea0SAnurag Kumar Vulisha 			   STEPS_0_MASK, ssc->steps & STEPS_0_MASK);
4384a33bea0SAnurag Kumar Vulisha 
4394a33bea0SAnurag Kumar Vulisha 	/* SSC steps [10:8] */
4404a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEPS_1_MSB,
4414a33bea0SAnurag Kumar Vulisha 			   STEPS_1_MASK,
4424a33bea0SAnurag Kumar Vulisha 			   (ssc->steps >> STEP_SIZE_SHIFT) & STEPS_1_MASK);
4434a33bea0SAnurag Kumar Vulisha 
4444a33bea0SAnurag Kumar Vulisha 	/* SSC step size [24:25] */
4454a33bea0SAnurag Kumar Vulisha 	step_size >>= STEP_SIZE_SHIFT;
4464a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_3_MSB,
4474a33bea0SAnurag Kumar Vulisha 			   STEP_SIZE_3_MASK, (step_size & STEP_SIZE_3_MASK) |
4484a33bea0SAnurag Kumar Vulisha 			   FORCE_STEP_SIZE | FORCE_STEPS);
4494a33bea0SAnurag Kumar Vulisha }
4504a33bea0SAnurag Kumar Vulisha 
4514a33bea0SAnurag Kumar Vulisha /* Configure the lane protocol. */
xpsgtr_lane_set_protocol(struct xpsgtr_phy * gtr_phy)4524a33bea0SAnurag Kumar Vulisha static void xpsgtr_lane_set_protocol(struct xpsgtr_phy *gtr_phy)
4534a33bea0SAnurag Kumar Vulisha {
4544a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
4554a33bea0SAnurag Kumar Vulisha 	u8 protocol = gtr_phy->protocol;
4564a33bea0SAnurag Kumar Vulisha 
4574a33bea0SAnurag Kumar Vulisha 	switch (gtr_phy->lane) {
4584a33bea0SAnurag Kumar Vulisha 	case 0:
4594a33bea0SAnurag Kumar Vulisha 		xpsgtr_clr_set(gtr_dev, ICM_CFG0, ICM_CFG0_L0_MASK, protocol);
4604a33bea0SAnurag Kumar Vulisha 		break;
4614a33bea0SAnurag Kumar Vulisha 	case 1:
4624a33bea0SAnurag Kumar Vulisha 		xpsgtr_clr_set(gtr_dev, ICM_CFG0, ICM_CFG0_L1_MASK,
4634a33bea0SAnurag Kumar Vulisha 			       protocol << ICM_CFG_SHIFT);
4644a33bea0SAnurag Kumar Vulisha 		break;
4654a33bea0SAnurag Kumar Vulisha 	case 2:
4664a33bea0SAnurag Kumar Vulisha 		xpsgtr_clr_set(gtr_dev, ICM_CFG1, ICM_CFG0_L0_MASK, protocol);
4674a33bea0SAnurag Kumar Vulisha 		break;
4684a33bea0SAnurag Kumar Vulisha 	case 3:
4694a33bea0SAnurag Kumar Vulisha 		xpsgtr_clr_set(gtr_dev, ICM_CFG1, ICM_CFG0_L1_MASK,
4704a33bea0SAnurag Kumar Vulisha 			       protocol << ICM_CFG_SHIFT);
4714a33bea0SAnurag Kumar Vulisha 		break;
4724a33bea0SAnurag Kumar Vulisha 	default:
4734a33bea0SAnurag Kumar Vulisha 		/* We already checked 0 <= lane <= 3 */
4744a33bea0SAnurag Kumar Vulisha 		break;
4754a33bea0SAnurag Kumar Vulisha 	}
4764a33bea0SAnurag Kumar Vulisha }
4774a33bea0SAnurag Kumar Vulisha 
4784a33bea0SAnurag Kumar Vulisha /* Bypass (de)scrambler and 8b/10b decoder and encoder. */
xpsgtr_bypass_scrambler_8b10b(struct xpsgtr_phy * gtr_phy)4794a33bea0SAnurag Kumar Vulisha static void xpsgtr_bypass_scrambler_8b10b(struct xpsgtr_phy *gtr_phy)
4804a33bea0SAnurag Kumar Vulisha {
4814a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TM_DIG_6, L0_TM_DIS_DESCRAMBLE_DECODER);
4824a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TX_DIG_61, L0_TM_DISABLE_SCRAMBLE_ENCODER);
4834a33bea0SAnurag Kumar Vulisha }
4844a33bea0SAnurag Kumar Vulisha 
4854a33bea0SAnurag Kumar Vulisha /* DP-specific initialization. */
xpsgtr_phy_init_dp(struct xpsgtr_phy * gtr_phy)4864a33bea0SAnurag Kumar Vulisha static void xpsgtr_phy_init_dp(struct xpsgtr_phy *gtr_phy)
4874a33bea0SAnurag Kumar Vulisha {
4884a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TXPMD_TM_45,
4894a33bea0SAnurag Kumar Vulisha 			 L0_TXPMD_TM_45_OVER_DP_MAIN |
4904a33bea0SAnurag Kumar Vulisha 			 L0_TXPMD_TM_45_ENABLE_DP_MAIN |
4914a33bea0SAnurag Kumar Vulisha 			 L0_TXPMD_TM_45_OVER_DP_POST1 |
4924a33bea0SAnurag Kumar Vulisha 			 L0_TXPMD_TM_45_OVER_DP_POST2 |
4934a33bea0SAnurag Kumar Vulisha 			 L0_TXPMD_TM_45_ENABLE_DP_POST2);
4944a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TX_ANA_TM_118,
4954a33bea0SAnurag Kumar Vulisha 			 L0_TX_ANA_TM_118_FORCE_17_0);
4964a33bea0SAnurag Kumar Vulisha }
4974a33bea0SAnurag Kumar Vulisha 
4984a33bea0SAnurag Kumar Vulisha /* SATA-specific initialization. */
xpsgtr_phy_init_sata(struct xpsgtr_phy * gtr_phy)4994a33bea0SAnurag Kumar Vulisha static void xpsgtr_phy_init_sata(struct xpsgtr_phy *gtr_phy)
5004a33bea0SAnurag Kumar Vulisha {
5014a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
5024a33bea0SAnurag Kumar Vulisha 
5034a33bea0SAnurag Kumar Vulisha 	xpsgtr_bypass_scrambler_8b10b(gtr_phy);
5044a33bea0SAnurag Kumar Vulisha 
5054a33bea0SAnurag Kumar Vulisha 	writel(gtr_phy->lane, gtr_dev->siou + SATA_CONTROL_OFFSET);
5064a33bea0SAnurag Kumar Vulisha }
5074a33bea0SAnurag Kumar Vulisha 
5084a33bea0SAnurag Kumar Vulisha /* SGMII-specific initialization. */
xpsgtr_phy_init_sgmii(struct xpsgtr_phy * gtr_phy)5094a33bea0SAnurag Kumar Vulisha static void xpsgtr_phy_init_sgmii(struct xpsgtr_phy *gtr_phy)
5104a33bea0SAnurag Kumar Vulisha {
5114a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
51237291f60SRobert Hancock 	u32 mask = PROT_BUS_WIDTH_MASK(gtr_phy->lane);
51337291f60SRobert Hancock 	u32 val = PROT_BUS_WIDTH_10 << PROT_BUS_WIDTH_SHIFT(gtr_phy->lane);
5144a33bea0SAnurag Kumar Vulisha 
5154a33bea0SAnurag Kumar Vulisha 	/* Set SGMII protocol TX and RX bus width to 10 bits. */
51637291f60SRobert Hancock 	xpsgtr_clr_set(gtr_dev, TX_PROT_BUS_WIDTH, mask, val);
51737291f60SRobert Hancock 	xpsgtr_clr_set(gtr_dev, RX_PROT_BUS_WIDTH, mask, val);
5184a33bea0SAnurag Kumar Vulisha 
5194a33bea0SAnurag Kumar Vulisha 	xpsgtr_bypass_scrambler_8b10b(gtr_phy);
5204a33bea0SAnurag Kumar Vulisha }
5214a33bea0SAnurag Kumar Vulisha 
5224a33bea0SAnurag Kumar Vulisha /* Configure TX de-emphasis and margining for DP. */
xpsgtr_phy_configure_dp(struct xpsgtr_phy * gtr_phy,unsigned int pre,unsigned int voltage)5234a33bea0SAnurag Kumar Vulisha static void xpsgtr_phy_configure_dp(struct xpsgtr_phy *gtr_phy, unsigned int pre,
5244a33bea0SAnurag Kumar Vulisha 				    unsigned int voltage)
5254a33bea0SAnurag Kumar Vulisha {
5264a33bea0SAnurag Kumar Vulisha 	static const u8 voltage_swing[4][4] = {
5274a33bea0SAnurag Kumar Vulisha 		{ 0x2a, 0x27, 0x24, 0x20 },
5284a33bea0SAnurag Kumar Vulisha 		{ 0x27, 0x23, 0x20, 0xff },
5294a33bea0SAnurag Kumar Vulisha 		{ 0x24, 0x20, 0xff, 0xff },
5304a33bea0SAnurag Kumar Vulisha 		{ 0xff, 0xff, 0xff, 0xff }
5314a33bea0SAnurag Kumar Vulisha 	};
5324a33bea0SAnurag Kumar Vulisha 	static const u8 pre_emphasis[4][4] = {
5334a33bea0SAnurag Kumar Vulisha 		{ 0x02, 0x02, 0x02, 0x02 },
5344a33bea0SAnurag Kumar Vulisha 		{ 0x01, 0x01, 0x01, 0xff },
5354a33bea0SAnurag Kumar Vulisha 		{ 0x00, 0x00, 0xff, 0xff },
5364a33bea0SAnurag Kumar Vulisha 		{ 0xff, 0xff, 0xff, 0xff }
5374a33bea0SAnurag Kumar Vulisha 	};
5384a33bea0SAnurag Kumar Vulisha 
5394a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TXPMD_TM_48, voltage_swing[pre][voltage]);
5404a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TX_ANA_TM_18, pre_emphasis[pre][voltage]);
5414a33bea0SAnurag Kumar Vulisha }
5424a33bea0SAnurag Kumar Vulisha 
5434a33bea0SAnurag Kumar Vulisha /*
5444a33bea0SAnurag Kumar Vulisha  * PHY Operations
5454a33bea0SAnurag Kumar Vulisha  */
5464a33bea0SAnurag Kumar Vulisha 
xpsgtr_phy_init_required(struct xpsgtr_phy * gtr_phy)5474a33bea0SAnurag Kumar Vulisha static bool xpsgtr_phy_init_required(struct xpsgtr_phy *gtr_phy)
5484a33bea0SAnurag Kumar Vulisha {
5494a33bea0SAnurag Kumar Vulisha 	/*
5504a33bea0SAnurag Kumar Vulisha 	 * As USB may save the snapshot of the states during hibernation, doing
5514a33bea0SAnurag Kumar Vulisha 	 * phy_init() will put the USB controller into reset, resulting in the
5524a33bea0SAnurag Kumar Vulisha 	 * losing of the saved snapshot. So try to avoid phy_init() for USB
5534a33bea0SAnurag Kumar Vulisha 	 * except when gtr_phy->skip_phy_init is false (this happens when FPD is
5544a33bea0SAnurag Kumar Vulisha 	 * shutdown during suspend or when gt lane is changed from current one)
5554a33bea0SAnurag Kumar Vulisha 	 */
5564a33bea0SAnurag Kumar Vulisha 	if (gtr_phy->protocol == ICM_PROTOCOL_USB && gtr_phy->skip_phy_init)
5574a33bea0SAnurag Kumar Vulisha 		return false;
5584a33bea0SAnurag Kumar Vulisha 	else
5594a33bea0SAnurag Kumar Vulisha 		return true;
5604a33bea0SAnurag Kumar Vulisha }
5614a33bea0SAnurag Kumar Vulisha 
5624a33bea0SAnurag Kumar Vulisha /*
5634a33bea0SAnurag Kumar Vulisha  * There is a functional issue in the GT. The TX termination resistance can be
5644a33bea0SAnurag Kumar Vulisha  * out of spec due to a issue in the calibration logic. This is the workaround
5654a33bea0SAnurag Kumar Vulisha  * to fix it, required for XCZU9EG silicon.
5664a33bea0SAnurag Kumar Vulisha  */
xpsgtr_phy_tx_term_fix(struct xpsgtr_phy * gtr_phy)5674a33bea0SAnurag Kumar Vulisha static int xpsgtr_phy_tx_term_fix(struct xpsgtr_phy *gtr_phy)
5684a33bea0SAnurag Kumar Vulisha {
5694a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
5704a33bea0SAnurag Kumar Vulisha 	u32 timeout = TIMEOUT_US;
5714a33bea0SAnurag Kumar Vulisha 	u32 nsw;
5724a33bea0SAnurag Kumar Vulisha 
5734a33bea0SAnurag Kumar Vulisha 	/* Enabling Test Mode control for CMN Rest */
5744a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_dev, TM_CMN_RST, TM_CMN_RST_MASK, TM_CMN_RST_SET);
5754a33bea0SAnurag Kumar Vulisha 
5764a33bea0SAnurag Kumar Vulisha 	/* Set Test Mode reset */
5774a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_dev, TM_CMN_RST, TM_CMN_RST_MASK, TM_CMN_RST_EN);
5784a33bea0SAnurag Kumar Vulisha 
5794a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, L3_TM_CALIB_DIG18, 0x00);
5804a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, L3_TM_CALIB_DIG19, L3_TM_OVERRIDE_NSW_CODE);
5814a33bea0SAnurag Kumar Vulisha 
5824a33bea0SAnurag Kumar Vulisha 	/*
5834a33bea0SAnurag Kumar Vulisha 	 * As a part of work around sequence for PMOS calibration fix,
5844a33bea0SAnurag Kumar Vulisha 	 * we need to configure any lane ICM_CFG to valid protocol. This
5854a33bea0SAnurag Kumar Vulisha 	 * will deassert the CMN_Resetn signal.
5864a33bea0SAnurag Kumar Vulisha 	 */
5874a33bea0SAnurag Kumar Vulisha 	xpsgtr_lane_set_protocol(gtr_phy);
5884a33bea0SAnurag Kumar Vulisha 
5894a33bea0SAnurag Kumar Vulisha 	/* Clear Test Mode reset */
5904a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_dev, TM_CMN_RST, TM_CMN_RST_MASK, TM_CMN_RST_SET);
5914a33bea0SAnurag Kumar Vulisha 
5924a33bea0SAnurag Kumar Vulisha 	dev_dbg(gtr_dev->dev, "calibrating...\n");
5934a33bea0SAnurag Kumar Vulisha 
5944a33bea0SAnurag Kumar Vulisha 	do {
5954a33bea0SAnurag Kumar Vulisha 		u32 reg = xpsgtr_read(gtr_dev, L3_CALIB_DONE_STATUS);
5964a33bea0SAnurag Kumar Vulisha 
5974a33bea0SAnurag Kumar Vulisha 		if ((reg & L3_CALIB_DONE) == L3_CALIB_DONE)
5984a33bea0SAnurag Kumar Vulisha 			break;
5994a33bea0SAnurag Kumar Vulisha 
6004a33bea0SAnurag Kumar Vulisha 		if (!--timeout) {
6014a33bea0SAnurag Kumar Vulisha 			dev_err(gtr_dev->dev, "calibration time out\n");
6024a33bea0SAnurag Kumar Vulisha 			return -ETIMEDOUT;
6034a33bea0SAnurag Kumar Vulisha 		}
6044a33bea0SAnurag Kumar Vulisha 
6054a33bea0SAnurag Kumar Vulisha 		udelay(1);
6064a33bea0SAnurag Kumar Vulisha 	} while (timeout > 0);
6074a33bea0SAnurag Kumar Vulisha 
6084a33bea0SAnurag Kumar Vulisha 	dev_dbg(gtr_dev->dev, "calibration done\n");
6094a33bea0SAnurag Kumar Vulisha 
6104a33bea0SAnurag Kumar Vulisha 	/* Reading NMOS Register Code */
6114a33bea0SAnurag Kumar Vulisha 	nsw = xpsgtr_read(gtr_dev, L0_TXPMA_ST_3) & L0_DN_CALIB_CODE;
6124a33bea0SAnurag Kumar Vulisha 
6134a33bea0SAnurag Kumar Vulisha 	/* Set Test Mode reset */
6144a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_dev, TM_CMN_RST, TM_CMN_RST_MASK, TM_CMN_RST_EN);
6154a33bea0SAnurag Kumar Vulisha 
6164a33bea0SAnurag Kumar Vulisha 	/* Writing NMOS register values back [5:3] */
6174a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, L3_TM_CALIB_DIG19, nsw >> L3_NSW_CALIB_SHIFT);
6184a33bea0SAnurag Kumar Vulisha 
6194a33bea0SAnurag Kumar Vulisha 	/* Writing NMOS register value [2:0] */
6204a33bea0SAnurag Kumar Vulisha 	xpsgtr_write(gtr_dev, L3_TM_CALIB_DIG18,
6214a33bea0SAnurag Kumar Vulisha 		     ((nsw & L3_TM_CALIB_DIG19_NSW) << L3_NSW_SHIFT) |
6224a33bea0SAnurag Kumar Vulisha 		     (1 << L3_NSW_PIPE_SHIFT));
6234a33bea0SAnurag Kumar Vulisha 
6244a33bea0SAnurag Kumar Vulisha 	/* Clear Test Mode reset */
6254a33bea0SAnurag Kumar Vulisha 	xpsgtr_clr_set(gtr_dev, TM_CMN_RST, TM_CMN_RST_MASK, TM_CMN_RST_SET);
6264a33bea0SAnurag Kumar Vulisha 
6274a33bea0SAnurag Kumar Vulisha 	return 0;
6284a33bea0SAnurag Kumar Vulisha }
6294a33bea0SAnurag Kumar Vulisha 
xpsgtr_phy_init(struct phy * phy)6304a33bea0SAnurag Kumar Vulisha static int xpsgtr_phy_init(struct phy *phy)
6314a33bea0SAnurag Kumar Vulisha {
6324a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
6334a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
6344a33bea0SAnurag Kumar Vulisha 	int ret = 0;
6354a33bea0SAnurag Kumar Vulisha 
6364a33bea0SAnurag Kumar Vulisha 	mutex_lock(&gtr_dev->gtr_mutex);
6374a33bea0SAnurag Kumar Vulisha 
63825d70083SPiyush Mehta 	/* Configure and enable the clock when peripheral phy_init call */
639687d6bccSSean Anderson 	if (clk_prepare_enable(gtr_dev->clk[gtr_phy->refclk]))
64025d70083SPiyush Mehta 		goto out;
64125d70083SPiyush Mehta 
6424a33bea0SAnurag Kumar Vulisha 	/* Skip initialization if not required. */
6434a33bea0SAnurag Kumar Vulisha 	if (!xpsgtr_phy_init_required(gtr_phy))
6444a33bea0SAnurag Kumar Vulisha 		goto out;
6454a33bea0SAnurag Kumar Vulisha 
6464a33bea0SAnurag Kumar Vulisha 	if (gtr_dev->tx_term_fix) {
6474a33bea0SAnurag Kumar Vulisha 		ret = xpsgtr_phy_tx_term_fix(gtr_phy);
6484a33bea0SAnurag Kumar Vulisha 		if (ret < 0)
6494a33bea0SAnurag Kumar Vulisha 			goto out;
6504a33bea0SAnurag Kumar Vulisha 
6514a33bea0SAnurag Kumar Vulisha 		gtr_dev->tx_term_fix = false;
6524a33bea0SAnurag Kumar Vulisha 	}
6534a33bea0SAnurag Kumar Vulisha 
6544a33bea0SAnurag Kumar Vulisha 	/* Enable coarse code saturation limiting logic. */
6554a33bea0SAnurag Kumar Vulisha 	xpsgtr_write_phy(gtr_phy, L0_TM_PLL_DIG_37, L0_TM_COARSE_CODE_LIMIT);
6564a33bea0SAnurag Kumar Vulisha 
6574a33bea0SAnurag Kumar Vulisha 	/*
6584a33bea0SAnurag Kumar Vulisha 	 * Configure the PLL, the lane protocol, and perform protocol-specific
6594a33bea0SAnurag Kumar Vulisha 	 * initialization.
6604a33bea0SAnurag Kumar Vulisha 	 */
6614a33bea0SAnurag Kumar Vulisha 	xpsgtr_configure_pll(gtr_phy);
6624a33bea0SAnurag Kumar Vulisha 	xpsgtr_lane_set_protocol(gtr_phy);
6634a33bea0SAnurag Kumar Vulisha 
6644a33bea0SAnurag Kumar Vulisha 	switch (gtr_phy->protocol) {
6654a33bea0SAnurag Kumar Vulisha 	case ICM_PROTOCOL_DP:
6664a33bea0SAnurag Kumar Vulisha 		xpsgtr_phy_init_dp(gtr_phy);
6674a33bea0SAnurag Kumar Vulisha 		break;
6684a33bea0SAnurag Kumar Vulisha 
6694a33bea0SAnurag Kumar Vulisha 	case ICM_PROTOCOL_SATA:
6704a33bea0SAnurag Kumar Vulisha 		xpsgtr_phy_init_sata(gtr_phy);
6714a33bea0SAnurag Kumar Vulisha 		break;
6724a33bea0SAnurag Kumar Vulisha 
6734a33bea0SAnurag Kumar Vulisha 	case ICM_PROTOCOL_SGMII:
6744a33bea0SAnurag Kumar Vulisha 		xpsgtr_phy_init_sgmii(gtr_phy);
6754a33bea0SAnurag Kumar Vulisha 		break;
6764a33bea0SAnurag Kumar Vulisha 	}
6774a33bea0SAnurag Kumar Vulisha 
6784a33bea0SAnurag Kumar Vulisha out:
6794a33bea0SAnurag Kumar Vulisha 	mutex_unlock(&gtr_dev->gtr_mutex);
6804a33bea0SAnurag Kumar Vulisha 	return ret;
6814a33bea0SAnurag Kumar Vulisha }
6824a33bea0SAnurag Kumar Vulisha 
xpsgtr_phy_exit(struct phy * phy)6834a33bea0SAnurag Kumar Vulisha static int xpsgtr_phy_exit(struct phy *phy)
6844a33bea0SAnurag Kumar Vulisha {
6854a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
68625d70083SPiyush Mehta 	struct xpsgtr_dev *gtr_dev = gtr_phy->dev;
6874a33bea0SAnurag Kumar Vulisha 
6884a33bea0SAnurag Kumar Vulisha 	gtr_phy->skip_phy_init = false;
6894a33bea0SAnurag Kumar Vulisha 
69025d70083SPiyush Mehta 	/* Ensure that disable clock only, which configure for lane */
691687d6bccSSean Anderson 	clk_disable_unprepare(gtr_dev->clk[gtr_phy->refclk]);
69225d70083SPiyush Mehta 
6934a33bea0SAnurag Kumar Vulisha 	return 0;
6944a33bea0SAnurag Kumar Vulisha }
6954a33bea0SAnurag Kumar Vulisha 
xpsgtr_phy_power_on(struct phy * phy)6964a33bea0SAnurag Kumar Vulisha static int xpsgtr_phy_power_on(struct phy *phy)
6974a33bea0SAnurag Kumar Vulisha {
6984a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
6994a33bea0SAnurag Kumar Vulisha 	int ret = 0;
7004a33bea0SAnurag Kumar Vulisha 
70189161cd0SPiyush Mehta 	/* Skip initialization if not required. */
70289161cd0SPiyush Mehta 	if (!xpsgtr_phy_init_required(gtr_phy))
70389161cd0SPiyush Mehta 		return ret;
704235d8b66SSean Anderson 	return xpsgtr_wait_pll_lock(phy);
7054a33bea0SAnurag Kumar Vulisha }
7064a33bea0SAnurag Kumar Vulisha 
xpsgtr_phy_configure(struct phy * phy,union phy_configure_opts * opts)7074a33bea0SAnurag Kumar Vulisha static int xpsgtr_phy_configure(struct phy *phy, union phy_configure_opts *opts)
7084a33bea0SAnurag Kumar Vulisha {
7094a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
7104a33bea0SAnurag Kumar Vulisha 
7114a33bea0SAnurag Kumar Vulisha 	if (gtr_phy->protocol != ICM_PROTOCOL_DP)
7124a33bea0SAnurag Kumar Vulisha 		return 0;
7134a33bea0SAnurag Kumar Vulisha 
7144a33bea0SAnurag Kumar Vulisha 	xpsgtr_phy_configure_dp(gtr_phy, opts->dp.pre[0], opts->dp.voltage[0]);
7154a33bea0SAnurag Kumar Vulisha 
7164a33bea0SAnurag Kumar Vulisha 	return 0;
7174a33bea0SAnurag Kumar Vulisha }
7184a33bea0SAnurag Kumar Vulisha 
7194a33bea0SAnurag Kumar Vulisha static const struct phy_ops xpsgtr_phyops = {
7204a33bea0SAnurag Kumar Vulisha 	.init		= xpsgtr_phy_init,
7214a33bea0SAnurag Kumar Vulisha 	.exit		= xpsgtr_phy_exit,
7224a33bea0SAnurag Kumar Vulisha 	.power_on	= xpsgtr_phy_power_on,
7234a33bea0SAnurag Kumar Vulisha 	.configure	= xpsgtr_phy_configure,
7244a33bea0SAnurag Kumar Vulisha 	.owner		= THIS_MODULE,
7254a33bea0SAnurag Kumar Vulisha };
7264a33bea0SAnurag Kumar Vulisha 
7274a33bea0SAnurag Kumar Vulisha /*
7284a33bea0SAnurag Kumar Vulisha  * OF Xlate Support
7294a33bea0SAnurag Kumar Vulisha  */
7304a33bea0SAnurag Kumar Vulisha 
7316959d236SSean Anderson /* Set the lane protocol and instance based on the PHY type and instance number. */
xpsgtr_set_lane_type(struct xpsgtr_phy * gtr_phy,u8 phy_type,unsigned int phy_instance)7324a33bea0SAnurag Kumar Vulisha static int xpsgtr_set_lane_type(struct xpsgtr_phy *gtr_phy, u8 phy_type,
7334a33bea0SAnurag Kumar Vulisha 				unsigned int phy_instance)
7344a33bea0SAnurag Kumar Vulisha {
7354a33bea0SAnurag Kumar Vulisha 	unsigned int num_phy_types;
7364a33bea0SAnurag Kumar Vulisha 
7374a33bea0SAnurag Kumar Vulisha 	switch (phy_type) {
7386959d236SSean Anderson 	case PHY_TYPE_SATA:
7396959d236SSean Anderson 		num_phy_types = 2;
7404a33bea0SAnurag Kumar Vulisha 		gtr_phy->protocol = ICM_PROTOCOL_SATA;
7414a33bea0SAnurag Kumar Vulisha 		break;
7426959d236SSean Anderson 	case PHY_TYPE_USB3:
7436959d236SSean Anderson 		num_phy_types = 2;
7444a33bea0SAnurag Kumar Vulisha 		gtr_phy->protocol = ICM_PROTOCOL_USB;
7454a33bea0SAnurag Kumar Vulisha 		break;
7466959d236SSean Anderson 	case PHY_TYPE_DP:
7476959d236SSean Anderson 		num_phy_types = 2;
7484a33bea0SAnurag Kumar Vulisha 		gtr_phy->protocol = ICM_PROTOCOL_DP;
7494a33bea0SAnurag Kumar Vulisha 		break;
7506959d236SSean Anderson 	case PHY_TYPE_PCIE:
7516959d236SSean Anderson 		num_phy_types = 4;
7524a33bea0SAnurag Kumar Vulisha 		gtr_phy->protocol = ICM_PROTOCOL_PCIE;
7534a33bea0SAnurag Kumar Vulisha 		break;
7546959d236SSean Anderson 	case PHY_TYPE_SGMII:
7556959d236SSean Anderson 		num_phy_types = 4;
7564a33bea0SAnurag Kumar Vulisha 		gtr_phy->protocol = ICM_PROTOCOL_SGMII;
7574a33bea0SAnurag Kumar Vulisha 		break;
7584a33bea0SAnurag Kumar Vulisha 	default:
7594a33bea0SAnurag Kumar Vulisha 		return -EINVAL;
7604a33bea0SAnurag Kumar Vulisha 	}
7614a33bea0SAnurag Kumar Vulisha 
7624a33bea0SAnurag Kumar Vulisha 	if (phy_instance >= num_phy_types)
7634a33bea0SAnurag Kumar Vulisha 		return -EINVAL;
7644a33bea0SAnurag Kumar Vulisha 
7656959d236SSean Anderson 	gtr_phy->instance = phy_instance;
7664a33bea0SAnurag Kumar Vulisha 	return 0;
7674a33bea0SAnurag Kumar Vulisha }
7684a33bea0SAnurag Kumar Vulisha 
7694a33bea0SAnurag Kumar Vulisha /*
7706959d236SSean Anderson  * Valid combinations of controllers and lanes (Interconnect Matrix). Each
7716959d236SSean Anderson  * "instance" represents one controller for a lane. For PCIe and DP, the
7726959d236SSean Anderson  * "instance" is the logical lane in the link. For SATA, USB, and SGMII,
7736959d236SSean Anderson  * the instance is the index of the controller.
7746959d236SSean Anderson  *
7756959d236SSean Anderson  * This information is only used to validate the devicetree reference, and is
7766959d236SSean Anderson  * not used when programming the hardware.
7774a33bea0SAnurag Kumar Vulisha  */
7784a33bea0SAnurag Kumar Vulisha static const unsigned int icm_matrix[NUM_LANES][CONTROLLERS_PER_LANE] = {
7796959d236SSean Anderson 	/* PCIe, SATA, USB, DP, SGMII */
7806959d236SSean Anderson 	{ 0, 0, 0, 1, 0 }, /* Lane 0 */
7816959d236SSean Anderson 	{ 1, 1, 0, 0, 1 }, /* Lane 1 */
7826959d236SSean Anderson 	{ 2, 0, 0, 1, 2 }, /* Lane 2 */
7836959d236SSean Anderson 	{ 3, 1, 1, 0, 3 }, /* Lane 3 */
7844a33bea0SAnurag Kumar Vulisha };
7854a33bea0SAnurag Kumar Vulisha 
7864a33bea0SAnurag Kumar Vulisha /* Translate OF phandle and args to PHY instance. */
xpsgtr_xlate(struct device * dev,const struct of_phandle_args * args)7874a33bea0SAnurag Kumar Vulisha static struct phy *xpsgtr_xlate(struct device *dev,
78800ca8a15SKrzysztof Kozlowski 				const struct of_phandle_args *args)
7894a33bea0SAnurag Kumar Vulisha {
7904a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev);
7914a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_phy *gtr_phy;
7924a33bea0SAnurag Kumar Vulisha 	unsigned int phy_instance;
7934a33bea0SAnurag Kumar Vulisha 	unsigned int phy_lane;
7944a33bea0SAnurag Kumar Vulisha 	unsigned int phy_type;
7954a33bea0SAnurag Kumar Vulisha 	unsigned int refclk;
7964a33bea0SAnurag Kumar Vulisha 	unsigned int i;
7974a33bea0SAnurag Kumar Vulisha 	int ret;
7984a33bea0SAnurag Kumar Vulisha 
7994a33bea0SAnurag Kumar Vulisha 	if (args->args_count != 4) {
8004a33bea0SAnurag Kumar Vulisha 		dev_err(dev, "Invalid number of cells in 'phy' property\n");
8014a33bea0SAnurag Kumar Vulisha 		return ERR_PTR(-EINVAL);
8024a33bea0SAnurag Kumar Vulisha 	}
8034a33bea0SAnurag Kumar Vulisha 
8044a33bea0SAnurag Kumar Vulisha 	/*
8054a33bea0SAnurag Kumar Vulisha 	 * Get the PHY parameters from the OF arguments and derive the lane
8064a33bea0SAnurag Kumar Vulisha 	 * type.
8074a33bea0SAnurag Kumar Vulisha 	 */
8084a33bea0SAnurag Kumar Vulisha 	phy_lane = args->args[0];
8094a33bea0SAnurag Kumar Vulisha 	if (phy_lane >= ARRAY_SIZE(gtr_dev->phys)) {
8104a33bea0SAnurag Kumar Vulisha 		dev_err(dev, "Invalid lane number %u\n", phy_lane);
8114a33bea0SAnurag Kumar Vulisha 		return ERR_PTR(-ENODEV);
8124a33bea0SAnurag Kumar Vulisha 	}
8134a33bea0SAnurag Kumar Vulisha 
8144a33bea0SAnurag Kumar Vulisha 	gtr_phy = &gtr_dev->phys[phy_lane];
8154a33bea0SAnurag Kumar Vulisha 	phy_type = args->args[1];
8164a33bea0SAnurag Kumar Vulisha 	phy_instance = args->args[2];
8174a33bea0SAnurag Kumar Vulisha 
818d79c6840SSean Anderson 	guard(mutex)(&gtr_phy->phy->mutex);
8194a33bea0SAnurag Kumar Vulisha 	ret = xpsgtr_set_lane_type(gtr_phy, phy_type, phy_instance);
8204a33bea0SAnurag Kumar Vulisha 	if (ret < 0) {
8214a33bea0SAnurag Kumar Vulisha 		dev_err(gtr_dev->dev, "Invalid PHY type and/or instance\n");
8224a33bea0SAnurag Kumar Vulisha 		return ERR_PTR(ret);
8234a33bea0SAnurag Kumar Vulisha 	}
8244a33bea0SAnurag Kumar Vulisha 
8254a33bea0SAnurag Kumar Vulisha 	refclk = args->args[3];
8264a33bea0SAnurag Kumar Vulisha 	if (refclk >= ARRAY_SIZE(gtr_dev->refclk_sscs) ||
8274a33bea0SAnurag Kumar Vulisha 	    !gtr_dev->refclk_sscs[refclk]) {
8284a33bea0SAnurag Kumar Vulisha 		dev_err(dev, "Invalid reference clock number %u\n", refclk);
8294a33bea0SAnurag Kumar Vulisha 		return ERR_PTR(-EINVAL);
8304a33bea0SAnurag Kumar Vulisha 	}
8314a33bea0SAnurag Kumar Vulisha 
8324a33bea0SAnurag Kumar Vulisha 	gtr_phy->refclk = refclk;
8334a33bea0SAnurag Kumar Vulisha 
8344a33bea0SAnurag Kumar Vulisha 	/*
8354a33bea0SAnurag Kumar Vulisha 	 * Ensure that the Interconnect Matrix is obeyed, i.e a given lane type
8364a33bea0SAnurag Kumar Vulisha 	 * is allowed to operate on the lane.
8374a33bea0SAnurag Kumar Vulisha 	 */
8384a33bea0SAnurag Kumar Vulisha 	for (i = 0; i < CONTROLLERS_PER_LANE; i++) {
8396959d236SSean Anderson 		if (icm_matrix[phy_lane][i] == gtr_phy->instance)
8404a33bea0SAnurag Kumar Vulisha 			return gtr_phy->phy;
8414a33bea0SAnurag Kumar Vulisha 	}
8424a33bea0SAnurag Kumar Vulisha 
8434a33bea0SAnurag Kumar Vulisha 	return ERR_PTR(-EINVAL);
8444a33bea0SAnurag Kumar Vulisha }
8454a33bea0SAnurag Kumar Vulisha 
8464a33bea0SAnurag Kumar Vulisha /*
84704490b62SSean Anderson  * DebugFS
84804490b62SSean Anderson  */
84904490b62SSean Anderson 
xpsgtr_status_read(struct seq_file * seq,void * data)85004490b62SSean Anderson static int xpsgtr_status_read(struct seq_file *seq, void *data)
85104490b62SSean Anderson {
85204490b62SSean Anderson 	struct device *dev = seq->private;
85304490b62SSean Anderson 	struct xpsgtr_phy *gtr_phy = dev_get_drvdata(dev);
85404490b62SSean Anderson 	struct clk *clk;
85504490b62SSean Anderson 	u32 pll_status;
85604490b62SSean Anderson 
85704490b62SSean Anderson 	mutex_lock(&gtr_phy->phy->mutex);
85804490b62SSean Anderson 	pll_status = xpsgtr_read_phy(gtr_phy, L0_PLL_STATUS_READ_1);
85904490b62SSean Anderson 	clk = gtr_phy->dev->clk[gtr_phy->refclk];
86004490b62SSean Anderson 
86104490b62SSean Anderson 	seq_printf(seq, "Lane:            %u\n", gtr_phy->lane);
86204490b62SSean Anderson 	seq_printf(seq, "Protocol:        %s\n",
86304490b62SSean Anderson 		   xpsgtr_icm_str[gtr_phy->protocol]);
86404490b62SSean Anderson 	seq_printf(seq, "Instance:        %u\n", gtr_phy->instance);
86504490b62SSean Anderson 	seq_printf(seq, "Reference clock: %u (%pC)\n", gtr_phy->refclk, clk);
86604490b62SSean Anderson 	seq_printf(seq, "Reference rate:  %lu\n", clk_get_rate(clk));
86704490b62SSean Anderson 	seq_printf(seq, "PLL locked:      %s\n",
86804490b62SSean Anderson 		   pll_status & PLL_STATUS_LOCKED ? "yes" : "no");
86904490b62SSean Anderson 
87004490b62SSean Anderson 	mutex_unlock(&gtr_phy->phy->mutex);
87104490b62SSean Anderson 	return 0;
87204490b62SSean Anderson }
87304490b62SSean Anderson 
87404490b62SSean Anderson /*
8754a33bea0SAnurag Kumar Vulisha  * Power Management
8764a33bea0SAnurag Kumar Vulisha  */
8774a33bea0SAnurag Kumar Vulisha 
xpsgtr_runtime_suspend(struct device * dev)878b3db66f6SPiyush Mehta static int xpsgtr_runtime_suspend(struct device *dev)
8794a33bea0SAnurag Kumar Vulisha {
8804a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev);
8814a33bea0SAnurag Kumar Vulisha 
8824a33bea0SAnurag Kumar Vulisha 	/* Save the snapshot ICM_CFG registers. */
8834a33bea0SAnurag Kumar Vulisha 	gtr_dev->saved_icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0);
8844a33bea0SAnurag Kumar Vulisha 	gtr_dev->saved_icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1);
8854a33bea0SAnurag Kumar Vulisha 
886*5af9b304SPiyush Mehta 	xpsgtr_save_lane_regs(gtr_dev);
887*5af9b304SPiyush Mehta 
8884a33bea0SAnurag Kumar Vulisha 	return 0;
8894a33bea0SAnurag Kumar Vulisha }
8904a33bea0SAnurag Kumar Vulisha 
xpsgtr_runtime_resume(struct device * dev)891b3db66f6SPiyush Mehta static int xpsgtr_runtime_resume(struct device *dev)
8924a33bea0SAnurag Kumar Vulisha {
8934a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev);
8944a33bea0SAnurag Kumar Vulisha 	unsigned int icm_cfg0, icm_cfg1;
8954a33bea0SAnurag Kumar Vulisha 	unsigned int i;
8964a33bea0SAnurag Kumar Vulisha 	bool skip_phy_init;
8974a33bea0SAnurag Kumar Vulisha 
898*5af9b304SPiyush Mehta 	xpsgtr_restore_lane_regs(gtr_dev);
899*5af9b304SPiyush Mehta 
9004a33bea0SAnurag Kumar Vulisha 	icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0);
9014a33bea0SAnurag Kumar Vulisha 	icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1);
9024a33bea0SAnurag Kumar Vulisha 
9034a33bea0SAnurag Kumar Vulisha 	/* Return if no GT lanes got configured before suspend. */
9044a33bea0SAnurag Kumar Vulisha 	if (!gtr_dev->saved_icm_cfg0 && !gtr_dev->saved_icm_cfg1)
9054a33bea0SAnurag Kumar Vulisha 		return 0;
9064a33bea0SAnurag Kumar Vulisha 
9074a33bea0SAnurag Kumar Vulisha 	/* Check if the ICM configurations changed after suspend. */
9084a33bea0SAnurag Kumar Vulisha 	if (icm_cfg0 == gtr_dev->saved_icm_cfg0 &&
9094a33bea0SAnurag Kumar Vulisha 	    icm_cfg1 == gtr_dev->saved_icm_cfg1)
9104a33bea0SAnurag Kumar Vulisha 		skip_phy_init = true;
9114a33bea0SAnurag Kumar Vulisha 	else
9124a33bea0SAnurag Kumar Vulisha 		skip_phy_init = false;
9134a33bea0SAnurag Kumar Vulisha 
9144a33bea0SAnurag Kumar Vulisha 	/* Update the skip_phy_init for all gtr_phy instances. */
9154a33bea0SAnurag Kumar Vulisha 	for (i = 0; i < ARRAY_SIZE(gtr_dev->phys); i++)
9164a33bea0SAnurag Kumar Vulisha 		gtr_dev->phys[i].skip_phy_init = skip_phy_init;
9174a33bea0SAnurag Kumar Vulisha 
9184a33bea0SAnurag Kumar Vulisha 	return 0;
9194a33bea0SAnurag Kumar Vulisha }
9204a33bea0SAnurag Kumar Vulisha 
921b3db66f6SPiyush Mehta static DEFINE_RUNTIME_DEV_PM_OPS(xpsgtr_pm_ops, xpsgtr_runtime_suspend,
922b3db66f6SPiyush Mehta 				 xpsgtr_runtime_resume, NULL);
9234a33bea0SAnurag Kumar Vulisha /*
9244a33bea0SAnurag Kumar Vulisha  * Probe & Platform Driver
9254a33bea0SAnurag Kumar Vulisha  */
9264a33bea0SAnurag Kumar Vulisha 
xpsgtr_get_ref_clocks(struct xpsgtr_dev * gtr_dev)9274a33bea0SAnurag Kumar Vulisha static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev)
9284a33bea0SAnurag Kumar Vulisha {
9294a33bea0SAnurag Kumar Vulisha 	unsigned int refclk;
9304a33bea0SAnurag Kumar Vulisha 
9314a33bea0SAnurag Kumar Vulisha 	for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->refclk_sscs); ++refclk) {
9324a33bea0SAnurag Kumar Vulisha 		unsigned long rate;
9334a33bea0SAnurag Kumar Vulisha 		unsigned int i;
9344a33bea0SAnurag Kumar Vulisha 		struct clk *clk;
9354a33bea0SAnurag Kumar Vulisha 		char name[8];
9364a33bea0SAnurag Kumar Vulisha 
9374a33bea0SAnurag Kumar Vulisha 		snprintf(name, sizeof(name), "ref%u", refclk);
9384a33bea0SAnurag Kumar Vulisha 		clk = devm_clk_get_optional(gtr_dev->dev, name);
93967097754SManish Narani 		if (IS_ERR(clk)) {
94025d70083SPiyush Mehta 			return dev_err_probe(gtr_dev->dev, PTR_ERR(clk),
94125d70083SPiyush Mehta 					     "Failed to get ref clock %u\n",
9423dbbc8e9SMichal Simek 					     refclk);
94367097754SManish Narani 		}
9444a33bea0SAnurag Kumar Vulisha 
9454a33bea0SAnurag Kumar Vulisha 		if (!clk)
9464a33bea0SAnurag Kumar Vulisha 			continue;
9474a33bea0SAnurag Kumar Vulisha 
94867097754SManish Narani 		gtr_dev->clk[refclk] = clk;
94967097754SManish Narani 
9504a33bea0SAnurag Kumar Vulisha 		/*
9514a33bea0SAnurag Kumar Vulisha 		 * Get the spread spectrum (SSC) settings for the reference
9524a33bea0SAnurag Kumar Vulisha 		 * clock rate.
9534a33bea0SAnurag Kumar Vulisha 		 */
9544a33bea0SAnurag Kumar Vulisha 		rate = clk_get_rate(clk);
9554a33bea0SAnurag Kumar Vulisha 
9564a33bea0SAnurag Kumar Vulisha 		for (i = 0 ; i < ARRAY_SIZE(ssc_lookup); i++) {
95776009ee7SSean Anderson 			/* Allow an error of 100 ppm */
95876009ee7SSean Anderson 			unsigned long error = ssc_lookup[i].refclk_rate / 10000;
95976009ee7SSean Anderson 
96076009ee7SSean Anderson 			if (abs(rate - ssc_lookup[i].refclk_rate) < error) {
9614a33bea0SAnurag Kumar Vulisha 				gtr_dev->refclk_sscs[refclk] = &ssc_lookup[i];
9624a33bea0SAnurag Kumar Vulisha 				break;
9634a33bea0SAnurag Kumar Vulisha 			}
9644a33bea0SAnurag Kumar Vulisha 		}
9654a33bea0SAnurag Kumar Vulisha 
9664a33bea0SAnurag Kumar Vulisha 		if (i == ARRAY_SIZE(ssc_lookup)) {
9674a33bea0SAnurag Kumar Vulisha 			dev_err(gtr_dev->dev,
9684a33bea0SAnurag Kumar Vulisha 				"Invalid rate %lu for reference clock %u\n",
9694a33bea0SAnurag Kumar Vulisha 				rate, refclk);
97025d70083SPiyush Mehta 			return -EINVAL;
9714a33bea0SAnurag Kumar Vulisha 		}
9724a33bea0SAnurag Kumar Vulisha 	}
9734a33bea0SAnurag Kumar Vulisha 
9744a33bea0SAnurag Kumar Vulisha 	return 0;
9754a33bea0SAnurag Kumar Vulisha }
9764a33bea0SAnurag Kumar Vulisha 
xpsgtr_probe(struct platform_device * pdev)9774a33bea0SAnurag Kumar Vulisha static int xpsgtr_probe(struct platform_device *pdev)
9784a33bea0SAnurag Kumar Vulisha {
9794a33bea0SAnurag Kumar Vulisha 	struct device_node *np = pdev->dev.of_node;
9804a33bea0SAnurag Kumar Vulisha 	struct xpsgtr_dev *gtr_dev;
9814a33bea0SAnurag Kumar Vulisha 	struct phy_provider *provider;
9824a33bea0SAnurag Kumar Vulisha 	unsigned int port;
9834a33bea0SAnurag Kumar Vulisha 	int ret;
9844a33bea0SAnurag Kumar Vulisha 
9854a33bea0SAnurag Kumar Vulisha 	gtr_dev = devm_kzalloc(&pdev->dev, sizeof(*gtr_dev), GFP_KERNEL);
9864a33bea0SAnurag Kumar Vulisha 	if (!gtr_dev)
9874a33bea0SAnurag Kumar Vulisha 		return -ENOMEM;
9884a33bea0SAnurag Kumar Vulisha 
9894a33bea0SAnurag Kumar Vulisha 	gtr_dev->dev = &pdev->dev;
9904a33bea0SAnurag Kumar Vulisha 	platform_set_drvdata(pdev, gtr_dev);
9914a33bea0SAnurag Kumar Vulisha 
9924a33bea0SAnurag Kumar Vulisha 	mutex_init(&gtr_dev->gtr_mutex);
9934a33bea0SAnurag Kumar Vulisha 
9944a33bea0SAnurag Kumar Vulisha 	if (of_device_is_compatible(np, "xlnx,zynqmp-psgtr"))
9954a33bea0SAnurag Kumar Vulisha 		gtr_dev->tx_term_fix =
9964a33bea0SAnurag Kumar Vulisha 			of_property_read_bool(np, "xlnx,tx-termination-fix");
9974a33bea0SAnurag Kumar Vulisha 
9984a33bea0SAnurag Kumar Vulisha 	/* Acquire resources. */
9994a33bea0SAnurag Kumar Vulisha 	gtr_dev->serdes = devm_platform_ioremap_resource_byname(pdev, "serdes");
10004a33bea0SAnurag Kumar Vulisha 	if (IS_ERR(gtr_dev->serdes))
10014a33bea0SAnurag Kumar Vulisha 		return PTR_ERR(gtr_dev->serdes);
10024a33bea0SAnurag Kumar Vulisha 
10034a33bea0SAnurag Kumar Vulisha 	gtr_dev->siou = devm_platform_ioremap_resource_byname(pdev, "siou");
10044a33bea0SAnurag Kumar Vulisha 	if (IS_ERR(gtr_dev->siou))
10054a33bea0SAnurag Kumar Vulisha 		return PTR_ERR(gtr_dev->siou);
10064a33bea0SAnurag Kumar Vulisha 
10074a33bea0SAnurag Kumar Vulisha 	ret = xpsgtr_get_ref_clocks(gtr_dev);
10084a33bea0SAnurag Kumar Vulisha 	if (ret)
10094a33bea0SAnurag Kumar Vulisha 		return ret;
10104a33bea0SAnurag Kumar Vulisha 
10114a33bea0SAnurag Kumar Vulisha 	/* Create PHYs. */
10124a33bea0SAnurag Kumar Vulisha 	for (port = 0; port < ARRAY_SIZE(gtr_dev->phys); ++port) {
10134a33bea0SAnurag Kumar Vulisha 		struct xpsgtr_phy *gtr_phy = &gtr_dev->phys[port];
10144a33bea0SAnurag Kumar Vulisha 		struct phy *phy;
10154a33bea0SAnurag Kumar Vulisha 
10164a33bea0SAnurag Kumar Vulisha 		gtr_phy->lane = port;
10174a33bea0SAnurag Kumar Vulisha 		gtr_phy->dev = gtr_dev;
10184a33bea0SAnurag Kumar Vulisha 
10194a33bea0SAnurag Kumar Vulisha 		phy = devm_phy_create(&pdev->dev, np, &xpsgtr_phyops);
10204a33bea0SAnurag Kumar Vulisha 		if (IS_ERR(phy)) {
10214a33bea0SAnurag Kumar Vulisha 			dev_err(&pdev->dev, "failed to create PHY\n");
102225d70083SPiyush Mehta 			return PTR_ERR(phy);
10234a33bea0SAnurag Kumar Vulisha 		}
10244a33bea0SAnurag Kumar Vulisha 
10254a33bea0SAnurag Kumar Vulisha 		gtr_phy->phy = phy;
10264a33bea0SAnurag Kumar Vulisha 		phy_set_drvdata(phy, gtr_phy);
102704490b62SSean Anderson 		debugfs_create_devm_seqfile(&phy->dev, "status", phy->debugfs,
102804490b62SSean Anderson 					    xpsgtr_status_read);
10294a33bea0SAnurag Kumar Vulisha 	}
10304a33bea0SAnurag Kumar Vulisha 
10314a33bea0SAnurag Kumar Vulisha 	/* Register the PHY provider. */
10324a33bea0SAnurag Kumar Vulisha 	provider = devm_of_phy_provider_register(&pdev->dev, xpsgtr_xlate);
10334a33bea0SAnurag Kumar Vulisha 	if (IS_ERR(provider)) {
10344a33bea0SAnurag Kumar Vulisha 		dev_err(&pdev->dev, "registering provider failed\n");
103525d70083SPiyush Mehta 		return PTR_ERR(provider);
10364a33bea0SAnurag Kumar Vulisha 	}
1037b3db66f6SPiyush Mehta 
1038b3db66f6SPiyush Mehta 	pm_runtime_set_active(gtr_dev->dev);
1039b3db66f6SPiyush Mehta 	pm_runtime_enable(gtr_dev->dev);
1040b3db66f6SPiyush Mehta 
1041b3db66f6SPiyush Mehta 	ret = pm_runtime_resume_and_get(gtr_dev->dev);
1042b3db66f6SPiyush Mehta 	if (ret < 0) {
1043b3db66f6SPiyush Mehta 		pm_runtime_disable(gtr_dev->dev);
104425d70083SPiyush Mehta 		return ret;
1045b3db66f6SPiyush Mehta 	}
1046b3db66f6SPiyush Mehta 
1047*5af9b304SPiyush Mehta 	gtr_dev->saved_regs = devm_kmalloc(gtr_dev->dev,
1048*5af9b304SPiyush Mehta 					   sizeof(save_reg_address),
1049*5af9b304SPiyush Mehta 					   GFP_KERNEL);
1050*5af9b304SPiyush Mehta 	if (!gtr_dev->saved_regs)
1051*5af9b304SPiyush Mehta 		return -ENOMEM;
1052*5af9b304SPiyush Mehta 
10534a33bea0SAnurag Kumar Vulisha 	return 0;
10544a33bea0SAnurag Kumar Vulisha }
10554a33bea0SAnurag Kumar Vulisha 
xpsgtr_remove(struct platform_device * pdev)10567dcb8668SUwe Kleine-König static void xpsgtr_remove(struct platform_device *pdev)
1057b3db66f6SPiyush Mehta {
1058b3db66f6SPiyush Mehta 	struct xpsgtr_dev *gtr_dev = platform_get_drvdata(pdev);
1059b3db66f6SPiyush Mehta 
1060b3db66f6SPiyush Mehta 	pm_runtime_disable(gtr_dev->dev);
1061b3db66f6SPiyush Mehta 	pm_runtime_put_noidle(gtr_dev->dev);
1062b3db66f6SPiyush Mehta 	pm_runtime_set_suspended(gtr_dev->dev);
1063b3db66f6SPiyush Mehta }
1064b3db66f6SPiyush Mehta 
10654a33bea0SAnurag Kumar Vulisha static const struct of_device_id xpsgtr_of_match[] = {
10664a33bea0SAnurag Kumar Vulisha 	{ .compatible = "xlnx,zynqmp-psgtr", },
10674a33bea0SAnurag Kumar Vulisha 	{ .compatible = "xlnx,zynqmp-psgtr-v1.1", },
10684a33bea0SAnurag Kumar Vulisha 	{},
10694a33bea0SAnurag Kumar Vulisha };
10704a33bea0SAnurag Kumar Vulisha MODULE_DEVICE_TABLE(of, xpsgtr_of_match);
10714a33bea0SAnurag Kumar Vulisha 
10724a33bea0SAnurag Kumar Vulisha static struct platform_driver xpsgtr_driver = {
10734a33bea0SAnurag Kumar Vulisha 	.probe = xpsgtr_probe,
10747dcb8668SUwe Kleine-König 	.remove_new = xpsgtr_remove,
10754a33bea0SAnurag Kumar Vulisha 	.driver = {
10764a33bea0SAnurag Kumar Vulisha 		.name = "xilinx-psgtr",
10774a33bea0SAnurag Kumar Vulisha 		.of_match_table	= xpsgtr_of_match,
1078b3db66f6SPiyush Mehta 		.pm =  pm_ptr(&xpsgtr_pm_ops),
10794a33bea0SAnurag Kumar Vulisha 	},
10804a33bea0SAnurag Kumar Vulisha };
10814a33bea0SAnurag Kumar Vulisha 
10824a33bea0SAnurag Kumar Vulisha module_platform_driver(xpsgtr_driver);
10834a33bea0SAnurag Kumar Vulisha 
10844a33bea0SAnurag Kumar Vulisha MODULE_AUTHOR("Xilinx Inc.");
10854a33bea0SAnurag Kumar Vulisha MODULE_LICENSE("GPL v2");
10864a33bea0SAnurag Kumar Vulisha MODULE_DESCRIPTION("Xilinx ZynqMP High speed Gigabit Transceiver");
1087