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