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 = >r_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(>r_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(>r_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 = >r_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)(>r_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(>r_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(>r_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(>r_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 = >r_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