diff --git a/drivers/ata/sata_xgene_serdes.c b/drivers/ata/sata_xgene_serdes.c
new file mode 100644
index 0000000..8c07e89
--- /dev/null
+++ b/drivers/ata/sata_xgene_serdes.c
@@ -0,0 +1,2004 @@
+/*
+ * AppliedMicro X-Gene SATA PHY driver
+ *
+ * Copyright (c) 2013, Applied Micro Circuits Corporation
+ * Author: Loc Ho <lho@apm.com>
+ *         Tuan Phan <tphan@apm.com>
+ *         Suman Tripathi <stripathi@apm.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/module.h>
+#include "sata_xgene.h"
+
+#define PHY_ERROR
+#undef PHY_DEBUG
+#undef PHYCSR_DEBUG
+
+#ifdef PHY_DEBUG
+#define PHYDEBUG(fmt, args...)		\
+	printk(KERN_INFO "XGENESATA PHY: " fmt "\n", ## args)
+#else
+#define PHYDEBUG(fmt, args...)
+#endif
+
+#ifdef PHYCSR_DEBUG
+#define PHYCSRDEBUG(fmt, args...)	\
+	printk(KERN_INFO "XGENESATA PHY CSR: " fmt "\n", ## args)
+#else
+#define PHYCSRDEBUG(fmt, args...)
+#endif
+
+#ifdef PHY_ERROR
+#define PHYERROR(fmt, args...)		\
+	printk(KERN_ERR "XGENESATA PHY ERROR: " fmt "\n", ## args)
+#else
+#define PHYERROR(fmt, args...)
+#endif
+
+/* SATA PHY CSR block offset */
+#define SATA_ETH_MUX_OFFSET		0x00007000
+#define SATA_SERDES_OFFSET		0x0000A000
+#define SATA_CLK_OFFSET			0x0000C000
+
+/* SATA PHY common tunning parameters.
+ *
+ * These are the common tunning PHY parameter. This are here to quick
+ * reference. They can be override from the control override registers.
+ */
+#define FBDIV_VAL_50M			0x77
+#define REFDIV_VAL_50M			0x1
+#define FBDIV_VAL_100M			0x3B
+#define REFDIV_VAL_100M			0x0
+#define FBDIV_VAL			FBDIV_VAL_50M
+#define REFDIV_VAL			REFDIV_VAL_50M
+
+/* SATA Clock/Reset CSR */
+#define SATACLKENREG_ADDR		0x00000000
+#define SATASRESETREG_ADDR		0x00000004
+#define  SATA_MEM_RESET_MASK		0x00000020
+#define  SATA_MEM_RESET_RD(src)		(((src) & 0x00000020)>>5)
+#define  SATA_SDS_RESET_MASK		0x00000004
+#define  SATA_CSR_RESET_MASK		0x00000001
+#define  SATA_CORE_RESET_MASK		0x00000002
+#define  SATA_PMCLK_RESET_MASK		0x00000010
+#define  SATA_PCLK_RESET_MASK		0x00000008
+
+/* SATA SDS CSR */
+#define SATA_ENET_SDS_PCS_CTL0_ADDR	0x00000000
+#define  REGSPEC_CFG_I_TX_WORDMODE0_SET(dst, src) \
+		(((dst) & ~0x00070000) | (((u32)(src)<<16) & 0x00070000))
+#define  REGSPEC_CFG_I_RX_WORDMODE0_SET(dst, src) \
+		(((dst) & ~0x00e00000) | (((u32)(src)<<21) & 0x00e00000))
+#define SATA_ENET_SDS_CTL1_ADDR		0x00000010
+#define  CFG_I_SPD_SEL_CDR_OVR1_SET(dst, src) \
+		(((dst) & ~0x0000000f) | (((u32)(src)) & 0x0000000f))
+#define SATA_ENET_SDS_CTL0_ADDR		0x0000000c
+#define  REGSPEC_CFG_I_CUSTOMER_PIN_MODE0_SET(dst, src) \
+		(((dst) & ~0x00007fff) | (((u32)(src)) & 0x00007fff))
+#define SATA_ENET_SDS_RST_CTL_ADDR	0x00000024
+#define SATA_ENET_SDS_IND_CMD_REG_ADDR	0x0000003c
+#define  CFG_IND_WR_CMD_MASK		0x00000001
+#define  CFG_IND_RD_CMD_MASK		0x00000002
+#define  CFG_IND_CMD_DONE_MASK		0x00000004
+#define  CFG_IND_ADDR_SET(dst, src) \
+		(((dst) & ~0x003ffff0) | (((u32)(src)<<4) & 0x003ffff0))
+#define SATA_ENET_SDS_IND_RDATA_REG_ADDR	0x00000040
+#define SATA_ENET_SDS_IND_WDATA_REG_ADDR	0x00000044
+#define SATA_ENET_CLK_MACRO_REG_ADDR	0x0000004c
+#define  I_RESET_B_SET(dst, src) \
+		(((dst) & ~0x00000001) | (((u32)(src)) & 0x00000001))
+#define  I_PLL_FBDIV_SET(dst, src) \
+		(((dst) & ~0x001ff000) | (((u32)(src)<<12) & 0x001ff000))
+#define  I_CUSTOMEROV_SET(dst, src) \
+		(((dst) & ~0x00000f80) | (((u32)(src)<<7) & 0x00000f80))
+#define  O_PLL_LOCK_RD(src)		(((src) & 0x40000000)>>30)
+#define  O_PLL_READY_RD(src)		(((src) & 0x80000000)>>31)
+
+/* SATA PHY clock CSR */
+#define KC_CLKMACRO_CMU_REGS_CMU_REG0_ADDR	0x20000
+#define  CMU_REG0_PDOWN_MASK			0x00004000
+#define  CMU_REG0_CAL_COUNT_RESOL_SET(dst, src) \
+		(((dst) & ~0x000000e0) | (((u32)(src) << 0x5) & 0x000000e0))
+#define KC_CLKMACRO_CMU_REGS_CMU_REG1_ADDR	0x20002
+#define  CMU_REG1_PLL_CP_SET(dst, src) \
+		(((dst) & ~0x00003c00) | (((u32)(src) << 0xa) & 0x00003c00))
+#define  CMU_REG1_PLL_MANUALCAL_SET(dst, src) \
+		(((dst) & ~0x00000008) | (((u32)(src) << 0x3) & 0x00000008))
+#define  CMU_REG1_PLL_CP_SEL_SET(dst, src) \
+		(((dst) & ~0x000003e0) | (((u32)(src) << 0x5) & 0x000003e0))
+#define KC_CLKMACRO_CMU_REGS_CMU_REG2_ADDR	0x20004
+#define  CMU_REG2_PLL_LFRES_SET(dst, src) \
+		(((dst) & ~0x0000001e) | (((u32)(src) << 0x1) & 0x0000001e))
+#define  CMU_REG2_PLL_FBDIV_SET(dst, src) \
+		(((dst) & ~0x00003fe0) | (((u32)(src) << 0x5) & 0x00003fe0))
+#define KC_CLKMACRO_CMU_REGS_CMU_REG3_ADDR	0x20006
+#define  CMU_REG3_VCOVARSEL_SET(dst, src) \
+		(((dst) & ~0x0000000f) | (((u32)(src) << 0x0) & 0x0000000f))
+#define  CMU_REG3_VCO_MOMSEL_INIT_SET(dst, src) \
+		(((dst) & ~0x000003f0) | (((u32)(src) << 0x4) & 0x000003f0))
+#define KC_CLKMACRO_CMU_REGS_CMU_REG4_ADDR	0x20008
+#define KC_CLKMACRO_CMU_REGS_CMU_REG5_ADDR	0x2000a
+#define  CMU_REG5_PLL_LFSMCAP_SET(dst, src) \
+		(((dst) & ~0x0000c000) | (((u32)(src) << 0xe) & 0x0000c000))
+#define  CMU_REG5_PLL_LOCK_RESOLUTION_SET(dst, src) \
+		(((dst) & ~0x0000000e) | (((u32)(src) << 0x1) & 0x0000000e))
+#define  CMU_REG5_PLL_LFCAP_SET(dst, src) \
+		(((dst) & ~0x00003000) | (((u32)(src) << 0xc) & 0x00003000))
+#define KC_CLKMACRO_CMU_REGS_CMU_REG6_ADDR	0x2000c
+#define  CMU_REG6_PLL_VREGTRIM_SET(dst, src) \
+		(((dst) & ~0x00000600) | (((u32)(src) << 0x9) & 0x00000600))
+#define  CMU_REG6_MAN_PVT_CAL_SET(dst, src) \
+		(((dst) & ~0x00000004) | (((u32)(src) << 0x2) & 0x00000004))
+#define KC_CLKMACRO_CMU_REGS_CMU_REG7_ADDR	0x2000e
+#define  CMU_REG7_PLL_CALIB_DONE_RD(src) \
+		((0x00004000 & (u32)(src)) >> 0xe)
+#define  CMU_REG7_VCO_CAL_FAIL_RD(src) \
+		((0x00000c00 & (u32)(src)) >> 0xa)
+#define KC_CLKMACRO_CMU_REGS_CMU_REG8_ADDR	0x20010
+#define KC_CLKMACRO_CMU_REGS_CMU_REG9_ADDR	0x20012
+#define KC_CLKMACRO_CMU_REGS_CMU_REG10_ADDR	0x20014
+#define KC_CLKMACRO_CMU_REGS_CMU_REG11_ADDR	0x20016
+#define KC_CLKMACRO_CMU_REGS_CMU_REG12_ADDR	0x20018
+#define KC_CLKMACRO_CMU_REGS_CMU_REG13_ADDR	0x2001a
+#define KC_CLKMACRO_CMU_REGS_CMU_REG14_ADDR	0x2001c
+#define KC_CLKMACRO_CMU_REGS_CMU_REG15_ADDR	0x2001e
+#define KC_CLKMACRO_CMU_REGS_CMU_REG16_ADDR	0x20020
+#define  CMU_REG16_PVT_DN_MAN_ENA_MASK		0x00000001
+#define  CMU_REG16_PVT_UP_MAN_ENA_MASK		0x00000002
+#define  CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(dst, src) \
+		(((dst) & ~0x0000001c) | (((u32)(src) << 0x2) & 0x0000001c))
+#define  CMU_REG16_CALIBRATION_DONE_OVERRIDE_SET(dst, src) \
+		(((dst) & ~0x00000040) | (((u32)(src) << 0x6) & 0x00000040))
+#define  CMU_REG16_BYPASS_PLL_LOCK_SET(dst, src) \
+		(((dst) & ~0x00000020) | (((u32)(src) << 0x5) & 0x00000020))
+#define KC_CLKMACRO_CMU_REGS_CMU_REG17_ADDR               0x20022
+#define  CMU_REG17_PVT_CODE_R2A_SET(dst, src) \
+		(((dst) & ~0x00007f00) | (((u32)(src) << 0x8) & 0x00007f00))
+#define  CMU_REG17_RESERVED_7_SET(dst, src) \
+		(((dst) & ~0x000000e0) | (((u32)(src) << 0x5) & 0x000000e0))
+#define  CMU_REG17_PVT_TERM_MAN_ENA_MASK			0x00008000
+#define KC_CLKMACRO_CMU_REGS_CMU_REG18_ADDR	0x20024
+#define KC_CLKMACRO_CMU_REGS_CMU_REG19_ADDR	0x20026
+#define KC_CLKMACRO_CMU_REGS_CMU_REG20_ADDR	0x20028
+#define KC_CLKMACRO_CMU_REGS_CMU_REG21_ADDR	0x2002a
+#define KC_CLKMACRO_CMU_REGS_CMU_REG22_ADDR	0x2002c
+#define KC_CLKMACRO_CMU_REGS_CMU_REG23_ADDR	0x2002e
+#define KC_CLKMACRO_CMU_REGS_CMU_REG24_ADDR	0x20030
+#define KC_CLKMACRO_CMU_REGS_CMU_REG25_ADDR	0x20032
+#define KC_CLKMACRO_CMU_REGS_CMU_REG26_ADDR	0x20034
+#define  CMU_REG26_FORCE_PLL_LOCK_SET(dst, src) \
+		(((dst) & ~0x00000001) | (((u32)(src) << 0x0) & 0x00000001))
+#define KC_CLKMACRO_CMU_REGS_CMU_REG27_ADDR	0x20036
+#define KC_CLKMACRO_CMU_REGS_CMU_REG28_ADDR	0x20038
+#define KC_CLKMACRO_CMU_REGS_CMU_REG29_ADDR	0x2003a
+#define KC_CLKMACRO_CMU_REGS_CMU_REG30_ADDR	0x2003c
+#define  CMU_REG30_LOCK_COUNT_SET(dst, src) \
+		(((dst) & ~0x00000006) | (((u32)(src) << 0x1) & 0x00000006))
+#define  CMU_REG30_PCIE_MODE_SET(dst, src) \
+		(((dst) & ~0x00000008) | (((u32)(src) << 0x3) & 0x00000008))
+#define KC_CLKMACRO_CMU_REGS_CMU_REG31_ADDR	0x2003e
+#define KC_CLKMACRO_CMU_REGS_CMU_REG32_ADDR	0x20040
+#define  CMU_REG32_FORCE_VCOCAL_START_MASK	0x00004000
+#define  CMU_REG32_PVT_CAL_WAIT_SEL_SET(dst, src) \
+		(((dst) & ~0x00000006) | (((u32)(src) << 0x1) & 0x00000006))
+#define  CMU_REG32_IREF_ADJ_SET(dst, src) \
+		(((dst) & ~0x00000180) | (((u32)(src) << 0x7) & 0x00000180))
+#define KC_CLKMACRO_CMU_REGS_CMU_REG33_ADDR	0x20042
+#define KC_CLKMACRO_CMU_REGS_CMU_REG34_ADDR	0x20044
+#define  CMU_REG34_VCO_CAL_VTH_LO_MAX_SET(dst, src) \
+		(((dst) & ~0x0000000f) | (((u32)(src) << 0x0) & 0x0000000f))
+#define  CMU_REG34_VCO_CAL_VTH_HI_MAX_SET(dst, src) \
+		(((dst) & ~0x00000f00) | (((u32)(src) << 0x8) & 0x00000f00))
+#define  CMU_REG34_VCO_CAL_VTH_LO_MIN_SET(dst, src) \
+		(((dst) & ~0x000000f0) | (((u32)(src) << 0x4) & 0x000000f0))
+#define  CMU_REG34_VCO_CAL_VTH_HI_MIN_SET(dst, src) \
+		(((dst) & ~0x0000f000) | (((u32)(src) << 0xc) & 0x0000f000))
+#define KC_SERDES_CMU_REGS_CMU_REG35_ADDR	0x46
+#define  CMU_REG35_PLL_SSC_MOD_SET(dst, src) \
+		(((dst) & ~0x0000fe00) | (((u32)(src) << 0x9) & 0x0000fe00))
+#define KC_SERDES_CMU_REGS_CMU_REG36_ADDR	0x48
+#define  CMU_REG36_PLL_SSC_EN_SET(dst, src) \
+		(((dst) & ~0x00000010) | (((u32)(src) << 0x4) & 0x00000010))
+#define  CMU_REG36_PLL_SSC_VSTEP_SET(dst, src) \
+		(((dst) & ~0x0000ffc0) | (((u32)(src) << 0x6) & 0x0000ffc0))
+#define  CMU_REG36_PLL_SSC_DSMSEL_SET(dst, src) \
+		(((dst) & ~0x00000020) | (((u32)(src) << 0x5) & 0x00000020))
+#define KC_CLKMACRO_CMU_REGS_CMU_REG35_ADDR	0x20046
+#define KC_CLKMACRO_CMU_REGS_CMU_REG36_ADDR	0x20048
+#define KC_CLKMACRO_CMU_REGS_CMU_REG37_ADDR	0x2004a
+#define KC_CLKMACRO_CMU_REGS_CMU_REG38_ADDR	0x2004c
+#define KC_CLKMACRO_CMU_REGS_CMU_REG39_ADDR	0x2004e
+
+/* SATA PHY RXTX CSR */
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG0_ADDR	0x400
+#define  CH0_RXTX_REG0_CTLE_EQ_HR_SET(dst, src) \
+		(((dst) & ~0x0000f800) | (((u32)(src) << 0xb) & 0x0000f800))
+#define  CH0_RXTX_REG0_CTLE_EQ_QR_SET(dst, src) \
+		(((dst) & ~0x000007c0) | (((u32)(src) << 0x6) & 0x000007c0))
+#define  CH0_RXTX_REG0_CTLE_EQ_FR_SET(dst, src) \
+		(((dst) & ~0x0000003e) | (((u32)(src) << 0x1) & 0x0000003e))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG1_ADDR	0x402
+#define  CH0_RXTX_REG1_RXACVCM_SET(dst, src) \
+		(((dst) & ~0x0000f000) | (((u32)(src) << 0xc) & 0x0000f000))
+#define  CH0_RXTX_REG1_CTLE_EQ_SET(dst, src) \
+		(((dst) & ~0x00000f80) | (((u32)(src) << 0x7) & 0x00000f80))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG2_ADDR	0x404
+#define  CH0_RXTX_REG2_VTT_ENA_SET(dst, src) \
+		(((dst) & ~0x00000100) | (((u32)(src) << 0x8) & 0x00000100))
+#define  CH0_RXTX_REG2_TX_FIFO_ENA_SET(dst, src) \
+		(((dst) & ~0x00000020) | (((u32)(src) << 0x5) & 0x00000020))
+#define  CH0_RXTX_REG2_VTT_SEL_SET(dst, src) \
+		(((dst) & ~0x000000c0) | (((u32)(src) << 0x6) & 0x000000c0))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG4_ADDR	0x408
+#define  CH0_RXTX_REG4_TX_LOOPBACK_BUF_EN_MASK			0x00000040
+#define  CH0_RXTX_REG4_TX_DATA_RATE_SET(dst, src) \
+		(((dst) & ~0x0000c000) | (((u32)(src) << 0xe) & 0x0000c000))
+#define  CH0_RXTX_REG4_TX_WORD_MODE_SET(dst, src) \
+		(((dst) & ~0x00003800) | (((u32)(src) << 0xb) & 0x00003800))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG5_ADDR	0x40a
+#define  CH0_RXTX_REG5_TX_CN1_SET(dst, src) \
+		(((dst) & ~0x0000f800) | (((u32)(src) << 0xb) & 0x0000f800))
+#define  CH0_RXTX_REG5_TX_CP1_SET(dst, src) \
+		(((dst) & ~0x000007e0) | (((u32)(src) << 0x5) & 0x000007e0))
+#define  CH0_RXTX_REG5_TX_CN2_SET(dst, src) \
+		(((dst) & ~0x0000001f) | (((u32)(src) << 0x0) & 0x0000001f))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG6_ADDR	0x40c
+#define  CH0_RXTX_REG6_TXAMP_CNTL_SET(dst, src) \
+		(((dst) & ~0x00000780) | (((u32)(src) << 0x7) & 0x00000780))
+#define  CH0_RXTX_REG6_TXAMP_ENA_SET(dst, src) \
+		(((dst) & ~0x00000040) | (((u32)(src) << 0x6) & 0x00000040))
+#define  CH0_RXTX_REG6_RX_BIST_ERRCNT_RD_SET(dst, src) \
+		(((dst) & ~0x00000001) | (((u32)(src) << 0x0) & 0x00000001))
+#define  CH0_RXTX_REG6_TX_IDLE_SET(dst, src) \
+		(((dst) & ~0x00000008) | (((u32)(src) << 0x3) & 0x00000008))
+#define  CH0_RXTX_REG6_RX_BIST_RESYNC_SET(dst, src) \
+		(((dst) & ~0x00000002) | (((u32)(src) << 0x1) & 0x00000002))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG7_ADDR	0x40e
+#define  CH0_RXTX_REG7_RESETB_RXD_MASK			0x00000100
+#define  CH0_RXTX_REG7_RESETB_RXA_MASK			0x00000080
+#define  CH0_RXTX_REG7_BIST_ENA_RX_SET(dst, src) \
+		(((dst) & ~0x00000040) | (((u32)(src) << 0x6) & 0x00000040))
+#define  CH0_RXTX_REG7_RX_WORD_MODE_SET(dst, src) \
+		(((dst) & ~0x00003800) | (((u32)(src) << 0xb) & 0x00003800))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG8_ADDR	0x410
+#define  CH0_RXTX_REG8_CDR_LOOP_ENA_SET(dst, src) \
+		(((dst) & ~0x00004000) | (((u32)(src) << 0xe) & 0x00004000))
+#define  CH0_RXTX_REG8_CDR_BYPASS_RXLOS_SET(dst, src) \
+		(((dst) & ~0x00000800) | (((u32)(src) << 0xb) & 0x00000800))
+#define  CH0_RXTX_REG8_SSC_ENABLE_SET(dst, src) \
+		(((dst) & ~0x00000200) | (((u32)(src) << 0x9) & 0x00000200))
+#define  CH0_RXTX_REG8_SD_VREF_SET(dst, src) \
+		(((dst) & ~0x000000f0) | (((u32)(src) << 0x4) & 0x000000f0))
+#define  CH0_RXTX_REG8_SD_DISABLE_SET(dst, src) \
+		(((dst) & ~0x00000100) | (((u32)(src) << 0x8) & 0x00000100))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG7_ADDR	0x40e
+#define  CH0_RXTX_REG7_RESETB_RXD_SET(dst, src) \
+		(((dst) & ~0x00000100) | (((u32)(src) << 0x8) & 0x00000100))
+#define  CH0_RXTX_REG7_RESETB_RXA_SET(dst, src) \
+		(((dst) & ~0x00000080) | (((u32)(src) << 0x7) & 0x00000080))
+#define  CH0_RXTX_REG7_LOOP_BACK_ENA_CTLE_MASK			0x00004000
+#define  CH0_RXTX_REG7_LOOP_BACK_ENA_CTLE_SET(dst, src) \
+		(((dst) & ~0x00004000) | (((u32)(src) << 0xe) & 0x00004000))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG11_ADDR	0x416
+#define  CH0_RXTX_REG11_PHASE_ADJUST_LIMIT_SET(dst, src) \
+		(((dst) & ~0x0000f800) | (((u32)(src) << 0xb) & 0x0000f800))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG12_ADDR	0x418
+#define  CH0_RXTX_REG12_LATCH_OFF_ENA_SET(dst, src) \
+		(((dst) & ~0x00002000) | (((u32)(src) << 0xd) & 0x00002000))
+#define  CH0_RXTX_REG12_SUMOS_ENABLE_SET(dst, src) \
+		(((dst) & ~0x00000004) | (((u32)(src) << 0x2) & 0x00000004))
+#define  CH0_RXTX_REG12_RX_DET_TERM_ENABLE_MASK		0x00000002
+#define  CH0_RXTX_REG12_RX_DET_TERM_ENABLE_SET(dst, src) \
+		(((dst) & ~0x00000002) | (((u32)(src) << 0x1) & 0x00000002))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG13_ADDR	0x41a
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG14_ADDR	0x41c
+#define CH0_RXTX_REG14_CLTE_LATCAL_MAN_PROG_SET(dst, src) \
+		(((dst) & ~0x0000003f) | (((u32)(src) << 0x0) & 0x0000003f))
+#define CH0_RXTX_REG14_CTLE_LATCAL_MAN_ENA_SET(dst, src) \
+		(((dst) & ~0x00000040) | (((u32)(src) << 0x6) & 0x00000040))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG26_ADDR	0x434
+#define  CH0_RXTX_REG26_PERIOD_ERROR_LATCH_SET(dst, src) \
+		(((dst) & ~0x00003800) | (((u32)(src) << 0xb) & 0x00003800))
+#define  CH0_RXTX_REG26_BLWC_ENA_SET(dst, src) \
+		(((dst) & ~0x00000008) | (((u32)(src) << 0x3) & 0x00000008))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG21_ADDR	0x42a
+#define  CH0_RXTX_REG21_DO_LATCH_CALOUT_RD(src) \
+		((0x0000fc00 & (u32)(src)) >> 0xa)
+#define  CH0_RXTX_REG21_XO_LATCH_CALOUT_RD(src) \
+		((0x000003f0 & (u32)(src)) >> 0x4)
+#define  CH0_RXTX_REG21_LATCH_CAL_FAIL_ODD_RD(src) \
+		((0x0000000f & (u32)(src)))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG22_ADDR	0x42c
+#define  CH0_RXTX_REG22_SO_LATCH_CALOUT_RD(src) \
+		((0x000003f0 & (u32)(src)) >> 0x4)
+#define  CH0_RXTX_REG22_EO_LATCH_CALOUT_RD(src) \
+		((0x0000fc00 & (u32)(src)) >> 0xa)
+#define  CH0_RXTX_REG22_LATCH_CAL_FAIL_EVEN_RD(src) \
+		((0x0000000f & (u32)(src)))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG23_ADDR	0x42e
+#define  CH0_RXTX_REG23_DE_LATCH_CALOUT_RD(src) \
+		((0x0000fc00 & (u32)(src)) >> 0xa)
+#define  CH0_RXTX_REG23_XE_LATCH_CALOUT_RD(src) \
+		((0x000003f0 & (u32)(src)) >> 0x4)
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG24_ADDR	0x430
+#define  CH0_RXTX_REG24_EE_LATCH_CALOUT_RD(src) \
+		((0x0000fc00 & (u32)(src)) >> 0xa)
+#define  CH0_RXTX_REG24_SE_LATCH_CALOUT_RD(src) \
+		((0x000003f0 & (u32)(src)) >> 0x4)
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG28_ADDR	0x438
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG31_ADDR	0x43e
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG38_ADDR	0x44c
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG39_ADDR	0x44e
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG40_ADDR	0x450
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG41_ADDR	0x452
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG42_ADDR	0x454
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG43_ADDR	0x456
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG44_ADDR	0x458
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG45_ADDR	0x45a
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG46_ADDR	0x45c
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG47_ADDR	0x45e
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG48_ADDR	0x460
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG49_ADDR	0x462
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG50_ADDR	0x464
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG51_ADDR	0x466
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG52_ADDR	0x468
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG53_ADDR	0x46a
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG54_ADDR	0x46c
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG55_ADDR	0x46e
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG61_ADDR	0x47a
+#define  CH0_RXTX_REG61_ISCAN_INBERT_SET(dst, src) \
+		(((dst) & ~0x00000010) | (((u32)(src) << 0x4) & 0x00000010))
+#define  CH0_RXTX_REG61_LOADFREQ_SHIFT_SET(dst, src) \
+		(((dst) & ~0x00000008) | (((u32)(src) << 0x3) & 0x00000008))
+#define  CH0_RXTX_REG61_EYE_COUNT_WIDTH_SEL_SET(dst, src) \
+		(((dst) & ~0x000000c0) | (((u32)(src) << 0x6) & 0x000000c0))
+#define  CH0_RXTX_REG61_SPD_SEL_CDR_SET(dst, src) \
+		(((dst) & ~0x00003c00) | (((u32)(src) << 0xa) & 0x00003c00))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG62_ADDR	0x47c
+#define  CH0_RXTX_REG62_PERIOD_H1_QLATCH_SET(dst, src) \
+		(((dst) & ~0x00003800) | (((u32)(src) << 0xb) & 0x00003800))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG81_ADDR	0x4a2
+
+#define  CH0_RXTX_REG89_MU_TH7_SET(dst, src) \
+		(((dst) & ~0x0000f800) | (((u32)(src) << 0xb) & 0x0000f800))
+#define  CH0_RXTX_REG89_MU_TH8_SET(dst, src) \
+		(((dst) & ~0x000007c0) | (((u32)(src) << 0x6) & 0x000007c0))
+#define  CH0_RXTX_REG89_MU_TH9_SET(dst, src) \
+		(((dst) & ~0x0000003e) | (((u32)(src) << 0x1) & 0x0000003e))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG96_ADDR	0x4c0
+#define  CH0_RXTX_REG96_MU_FREQ1_SET(dst, src) \
+		(((dst) & ~0x0000f800) | (((u32)(src) << 0xb) & 0x0000f800))
+#define  CH0_RXTX_REG96_MU_FREQ2_SET(dst, src) \
+		(((dst) & ~0x000007c0) | (((u32)(src) << 0x6) & 0x000007c0))
+#define  CH0_RXTX_REG96_MU_FREQ3_SET(dst, src) \
+		(((dst) & ~0x0000003e) | (((u32)(src) << 0x1) & 0x0000003e))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG99_ADDR	0x4c6
+#define  CH0_RXTX_REG99_MU_PHASE1_SET(dst, src) \
+		(((dst) & ~0x0000f800) | (((u32)(src) << 0xb) & 0x0000f800))
+#define  CH0_RXTX_REG99_MU_PHASE2_SET(dst, src) \
+		(((dst) & ~0x000007c0) | (((u32)(src) << 0x6) & 0x000007c0))
+#define  CH0_RXTX_REG99_MU_PHASE3_SET(dst, src) \
+		(((dst) & ~0x0000003e) | (((u32)(src) << 0x1) & 0x0000003e))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG102_ADDR	0x4cc
+#define  CH0_RXTX_REG102_FREQLOOP_LIMIT_SET(dst, src) \
+		(((dst) & ~0x00000060) | (((u32)(src) << 0x5) & 0x00000060))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG114_ADDR	0x4e4
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG121_ADDR	0x4f2
+#define  CH0_RXTX_REG121_SUMOS_CAL_CODE_RD(src) \
+		((0x0000003e & (u32)(src)) >> 0x1)
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG125_ADDR	0x4fa
+#define  CH0_RXTX_REG125_PQ_REG_SET(dst, src) \
+		(((dst) & ~0x0000fe00) | (((u32)(src) << 0x9) & 0x0000fe00))
+#define  CH0_RXTX_REG125_SIGN_PQ_SET(dst, src) \
+		(((dst) & ~0x00000100) | (((u32)(src) << 0x8) & 0x00000100))
+#define  CH0_RXTX_REG125_SIGN_PQ_2C_SET(dst, src) \
+		(((dst) & ~0x00000080) | (((u32)(src) << 0x7) & 0x00000080))
+#define  CH0_RXTX_REG125_PHZ_MANUALCODE_SET(dst, src) \
+		(((dst) & ~0x0000007c) | (((u32)(src) << 0x2) & 0x0000007c))
+#define  CH0_RXTX_REG125_PHZ_MANUAL_SET(dst, src) \
+		(((dst) & ~0x00000002) | (((u32)(src) << 0x1) & 0x00000002))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG127_ADDR	0x4fe
+#define  CH0_RXTX_REG127_FORCE_SUM_CAL_START_MASK	0x00000002
+#define  CH0_RXTX_REG127_FORCE_LAT_CAL_START_MASK	0x00000004
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG127_ADDR	0x6fe
+#define  CH1_RXTX_REG127_FORCE_SUM_CAL_START_SET(dst, src) \
+		(((dst) & ~0x00000002) | (((u32)(src) << 0x1) & 0x00000002))
+#define  CH1_RXTX_REG127_FORCE_LAT_CAL_START_SET(dst, src) \
+		(((dst) & ~0x00000004) | (((u32)(src) << 0x2) & 0x00000004))
+#define  CH0_RXTX_REG127_LATCH_MAN_CAL_ENA_SET(dst, src) \
+		(((dst) & ~0x00000008) | (((u32)(src) << 0x3) & 0x00000008))
+#define  CH0_RXTX_REG127_DO_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x0000fc00) | (((u32)(src) << 0xa) & 0x0000fc00))
+#define  CH0_RXTX_REG127_XO_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x000003f0) | (((u32)(src) << 0x4) & 0x000003f0))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG128_ADDR	0x500
+#define  CH0_RXTX_REG128_LATCH_CAL_WAIT_SEL_SET(dst, src) \
+		(((dst) & ~0x0000000c) | (((u32)(src) << 0x2) & 0x0000000c))
+#define  CH0_RXTX_REG128_EO_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x0000fc00) | (((u32)(src) << 0xa) & 0x0000fc00))
+#define CH0_RXTX_REG128_SO_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x000003f0) | (((u32)(src) << 0x4) & 0x000003f0))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG129_ADDR	0x502
+#define CH0_RXTX_REG129_DE_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x0000fc00) | (((u32)(src) << 0xa) & 0x0000fc00))
+#define CH0_RXTX_REG129_XE_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x000003f0) | (((u32)(src) << 0x4) & 0x000003f0))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG130_ADDR	0x504
+#define  CH0_RXTX_REG130_EE_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x0000fc00) | (((u32)(src) << 0xa) & 0x0000fc00))
+#define  CH0_RXTX_REG130_SE_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x000003f0) | (((u32)(src) << 0x4) & 0x000003f0))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG145_ADDR	0x522
+#define  CH0_RXTX_REG145_TX_IDLE_SATA_SET(dst, src) \
+		(((dst) & ~0x00000001) | (((u32)(src) << 0x0) & 0x00000001))
+#define  CH0_RXTX_REG145_RXES_ENA_SET(dst, src) \
+		(((dst) & ~0x00000002) | (((u32)(src) << 0x1) & 0x00000002))
+#define  CH0_RXTX_REG145_RXDFE_CONFIG_SET(dst, src) \
+		(((dst) & ~0x0000c000) | (((u32)(src) << 0xe) & 0x0000c000))
+#define  CH0_RXTX_REG145_RXVWES_LATENA_SET(dst, src) \
+		(((dst) & ~0x00000004) | (((u32)(src) << 0x2) & 0x00000004))
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG147_ADDR	0x526
+#define KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG148_ADDR	0x528
+
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG4_ADDR	0x608
+#define  CH1_RXTX_REG4_TX_LOOPBACK_BUF_EN_SET(dst, src) \
+		(((dst) & ~0x00000040) | (((u32)(src) << 0x6) & 0x00000040))
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG7_ADDR	0x60e
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG13_ADDR	0x61a
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG38_ADDR	0x64c
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG39_ADDR	0x64e
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG40_ADDR	0x650
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG41_ADDR	0x652
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG42_ADDR	0x654
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG43_ADDR	0x656
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG44_ADDR	0x658
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG45_ADDR	0x65a
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG46_ADDR	0x65c
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG47_ADDR	0x65e
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG48_ADDR	0x660
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG49_ADDR	0x662
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG50_ADDR	0x664
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG51_ADDR	0x666
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG52_ADDR	0x668
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG53_ADDR	0x66a
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG54_ADDR	0x66c
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG55_ADDR	0x66e
+#define KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG121_ADDR	0x6f2
+
+/* SATA/ENET Shared CSR */
+#define SATA_ENET_CONFIG_REG_ADDR		0x00000000
+#define  CFG_SATA_ENET_SELECT_MASK		0x00000001
+
+/* SATA SERDES CMU CSR */
+#define KC_SERDES_CMU_REGS_CMU_REG0_ADDR	0x0
+#define  CMU_REG0_PLL_REF_SEL_MASK		0x00002000
+#define CMU_REG0_PLL_REF_SEL_SHIFT_MASK		0xd
+#define CMU_REG0_PLL_REF_SEL_SET(dst, src)	\
+		(((dst) & ~0x00002000) | (((u32)(src) << 0xd) & 0x00002000))
+#define KC_SERDES_CMU_REGS_CMU_REG1_ADDR	0x2
+#define  CMU_REG1_REFCLK_CMOS_SEL_MASK		0x00000001
+#define CMU_REG1_REFCLK_CMOS_SEL_SHIFT_MASK	0x0
+#define CMU_REG1_REFCLK_CMOS_SEL_SET(dst, src)	\
+		(((dst) & ~0x00000001) | (((u32)(src) << 0x0) & 0x00000001))
+#define KC_SERDES_CMU_REGS_CMU_REG2_ADDR	0x4
+#define  CMU_REG2_PLL_REFDIV_SET(dst, src) \
+		(((dst) & ~0x0000c000) | (((u32)(src) << 0xe) & 0x0000c000))
+#define KC_SERDES_CMU_REGS_CMU_REG3_ADDR	0x6
+#define  CMU_REG3_VCO_MANMOMSEL_SET(dst, src) \
+		(((dst) & ~0x0000fc00) | (((u32)(src) << 0xa) & 0x0000fc00))
+#define KC_SERDES_CMU_REGS_CMU_REG5_ADDR	0xa
+#define  CMU_REG5_PLL_RESETB_MASK		0x00000001
+#define KC_SERDES_CMU_REGS_CMU_REG6_ADDR	0xc
+#define KC_SERDES_CMU_REGS_CMU_REG7_ADDR	0xe
+#define KC_SERDES_CMU_REGS_CMU_REG9_ADDR	0x12
+#define  CMU_REG9_TX_WORD_MODE_CH1_SET(dst, src) \
+		(((dst) & ~0x00000380) | (((u32)(src) << 0x7) & 0x00000380))
+#define  CMU_REG9_TX_WORD_MODE_CH0_SET(dst, src) \
+		(((dst) & ~0x00000070) | (((u32)(src) << 0x4) & 0x00000070))
+#define  CMU_REG9_PLL_POST_DIVBY2_SET(dst, src) \
+		(((dst) & ~0x00000008) | (((u32)(src) << 0x3) & 0x00000008))
+#define KC_SERDES_CMU_REGS_CMU_REG12_ADDR	0x18
+#define  CMU_REG12_STATE_DELAY9_SET(dst, src) \
+		(((dst) & ~0x000000f0) | (((u32)(src) << 0x4) & 0x000000f0))
+#define KC_SERDES_CMU_REGS_CMU_REG13_ADDR	0x1a
+#define KC_SERDES_CMU_REGS_CMU_REG14_ADDR	0x1c
+#define KC_SERDES_CMU_REGS_CMU_REG15_ADDR	0x1e
+#define KC_SERDES_CMU_REGS_CMU_REG16_ADDR	0x20
+#define KC_SERDES_CMU_REGS_CMU_REG17_ADDR	0x22
+#define KC_SERDES_CMU_REGS_CMU_REG26_ADDR	0x34
+#define KC_SERDES_CMU_REGS_CMU_REG30_ADDR	0x3c
+#define KC_SERDES_CMU_REGS_CMU_REG31_ADDR	0x3e
+#define KC_SERDES_CMU_REGS_CMU_REG32_ADDR	0x40
+#define  CMU_REG32_FORCE_VCOCAL_START_MASK	0x00004000
+#define KC_SERDES_CMU_REGS_CMU_REG34_ADDR	0x44
+#define KC_SERDES_CMU_REGS_CMU_REG37_ADDR	0x4a
+
+/* PCIE SATA Serdes CSR (CSR shared with the PCIe) */
+#define SM_PCIE_CLKRST_CSR_PCIE_SRST_ADDR	0xc000
+#define SM_PCIE_CLKRST_CSR_PCIE_CLKEN_ADDR	0xc008
+#define SM_PCIE_X8_SDS_CSR_REGS_PCIE_SDS_IND_WDATA_REG_ADDR	0xa01c
+#define SM_PCIE_X8_SDS_CSR_REGS_PCIE_SDS_IND_CMD_REG_ADDR	0xa014
+#define  PCIE_SDS_IND_CMD_REG_CFG_IND_ADDR_SET(dst, src) \
+		(((dst) & ~0x003ffff0) | (((u32)(src) << 0x4) & 0x003ffff0))
+#define  PCIE_SDS_IND_CMD_REG_CFG_IND_WR_CMD_SET(dst, src) \
+		(((dst) & ~0x00000001) | (((u32)(src) << 0x0) & 0x00000001))
+#define SM_PCIE_X8_SDS_CSR_REGS_PCIE_SDS_IND_RDATA_REG_ADDR	0xa018
+#define SM_PCIE_X8_SDS_CSR_REGS_PCIE_CLK_MACRO_REG_ADDR		0xa094
+#define  PCIE_SDS_IND_CMD_REG_CFG_IND_CMD_DONE_RD(src) \
+		((0x00000004 & (uint32_t)(src)) >> 0x2)
+#define  PCIE_SDS_IND_CMD_REG_CFG_IND_CMD_DONE_SET(dst, src) \
+		(((dst) & ~0x00000004) | (((u32)(src) << 0x2) & 0x00000004))
+#define  PCIE_SDS_IND_CMD_REG_CFG_IND_RD_CMD_SET(dst, src) \
+		(((dst) & ~0x00000002) | (((u32)(src) << 0x1) & 0x00000002))
+#define PCIE_CLK_MACRO_REG_I_RESET_B_SET(dst, src) \
+		(((dst) & ~0x00000001) | (((u32)(src) << 0x0) & 0x00000001))
+#define PCIE_CLK_MACRO_REG_I_CUSTOMEROV_SET(dst, src) \
+		(((dst) & ~0x00000f80) | (((u32)(src) << 0x7) & 0x00000f80))
+#define PCIE_CLK_MACRO_REG_O_PLL_READY_RD(src) \
+		((0x80000000 & (u32)(src)) >> 0x1f)
+#define PCIE_CLK_MACRO_REG_I_PLL_FBDIV_SET(dst, src) \
+		(((dst) & ~0x001ff000) | (((u32)(src) << 0xc) & 0x001ff000))
+#define PCIE_CLK_MACRO_REG_O_PLL_LOCK_RD(src)	\
+		((0x40000000 & (u32)(src)) >> 0x1e)
+
+static void xgene_serdes_wr(void *csr_base, u32 indirect_cmd_reg,
+			    u32 indirect_data_reg, u32 addr, u32 data)
+{
+	u32 val;
+	u32 cmd;
+
+	cmd = CFG_IND_WR_CMD_MASK | CFG_IND_CMD_DONE_MASK;
+	cmd = (addr << 4) | cmd;
+	xgene_ahci_out32(csr_base + indirect_data_reg, data);
+	xgene_ahci_out32(csr_base + indirect_cmd_reg, cmd);
+	/* Add an barrier - very important please don't remove */
+	wmb();
+	/* Ignore first read */
+	xgene_ahci_in32(csr_base + indirect_cmd_reg, &val);
+	/* Allow Serdes to get reflected */
+	xgene_ahci_delayus(1000);
+	do {
+		xgene_ahci_in32(csr_base + indirect_cmd_reg, &val);
+	} while (!(val & CFG_IND_CMD_DONE_MASK));
+}
+
+static void xgene_serdes_rd(void *csr_base, u32 indirect_cmd_reg,
+			    u32 indirect_data_reg, u32 addr, u32 *data)
+{
+	u32 val;
+	u32 cmd;
+
+	cmd = CFG_IND_RD_CMD_MASK | CFG_IND_CMD_DONE_MASK;
+	cmd = (addr << 4) | cmd;
+	xgene_ahci_out32(csr_base + indirect_cmd_reg, cmd);
+	/* Add an barrier - very important please don't remove */
+	wmb();
+	/* Ignore first read */
+	xgene_ahci_in32(csr_base + indirect_cmd_reg, &val);
+	/* Allow Serdes to get reflected */
+	xgene_ahci_delayus(1000);
+	do {
+		xgene_ahci_in32(csr_base + indirect_cmd_reg, &val);
+	} while (!(val & CFG_IND_CMD_DONE_MASK));
+	xgene_ahci_in32(csr_base + indirect_data_reg, data);
+}
+
+/* X-Gene Serdes write helper for SATA port 0, 1, 2, and 3 */
+static void xgene_sds_wr(void *csr_base, u32 addr, u32 data)
+{
+	u32 val;
+	xgene_serdes_wr(csr_base, SATA_ENET_SDS_IND_CMD_REG_ADDR,
+			SATA_ENET_SDS_IND_WDATA_REG_ADDR, addr, data);
+	xgene_serdes_rd(csr_base, SATA_ENET_SDS_IND_CMD_REG_ADDR,
+			SATA_ENET_SDS_IND_RDATA_REG_ADDR, addr, &val);
+	PHYCSRDEBUG("SDS WR addr 0x%X value 0x%08X <-> 0x%08X", addr, data,
+		    val);
+}
+
+/* X-Gene Serdes read helper for SATA port 0, 1, 2, and 3 */
+static void xgene_sds_rd(void *csr_base, u32 addr, u32 *data)
+{
+	xgene_serdes_rd(csr_base, SATA_ENET_SDS_IND_CMD_REG_ADDR,
+			SATA_ENET_SDS_IND_RDATA_REG_ADDR, addr, data);
+	PHYCSRDEBUG("SDS RD addr 0x%X value 0x%08X", addr, *data);
+}
+
+/* X-Gene Serdes toggle helper for SATA port 0, 1, 2, and 3 */
+static void xgene_sds_toggle1to0(void *csr_base, u32 addr, u32 bits,
+				 u32 delayus)
+{
+	u32 val;
+	xgene_sds_rd(csr_base, addr, &val);
+	val |= bits;
+	xgene_sds_wr(csr_base, addr, val);
+	xgene_ahci_delayus(delayus);
+	xgene_sds_rd(csr_base, addr, &val);
+	val &= ~bits;
+	xgene_sds_wr(csr_base, addr, val);
+}
+
+/* X-Gene Serdes clear bits helper for SATA port 0, 1, 2, and 3 */
+static void xgene_sds_clrbits(void *csr_base, u32 addr, u32 bits)
+{
+	u32 val;
+	xgene_sds_rd(csr_base, addr, &val);
+	val &= ~bits;
+	xgene_sds_wr(csr_base, addr, val);
+}
+
+/* X-Gene Serdes set bits helper for SATA port 0, 1, 2, and 3 */
+static void xgene_sds_setbits(void *csr_base, u32 addr, u32 bits)
+{
+	u32 val;
+	xgene_sds_rd(csr_base, addr, &val);
+	val |= bits;
+	xgene_sds_wr(csr_base, addr, val);
+}
+
+/* X-Gene Serdes write helper for SATA port 4 and 5 */
+static void xgene_sds_pcie_wr(void *csr_base, u32 addr, u32 data)
+{
+	u32 val;
+	xgene_serdes_wr(csr_base,
+			SM_PCIE_X8_SDS_CSR_REGS_PCIE_SDS_IND_CMD_REG_ADDR,
+			SM_PCIE_X8_SDS_CSR_REGS_PCIE_SDS_IND_WDATA_REG_ADDR,
+			addr, data);
+	xgene_serdes_rd(csr_base,
+			SM_PCIE_X8_SDS_CSR_REGS_PCIE_SDS_IND_CMD_REG_ADDR,
+			SM_PCIE_X8_SDS_CSR_REGS_PCIE_SDS_IND_RDATA_REG_ADDR,
+			addr, &val);
+	xgene_ahci_delayus(122);	/* Allow Serdes to get reflected */
+	PHYCSRDEBUG("PCIE SDS WR addr 0x%X value 0x%08X <-> 0x%08X", addr,
+		    data, val);
+}
+
+/* X-Gene Serdes read helper for SATA port 4 and 5 */
+static void xgene_sds_pcie_rd(void *csr_base, u32 addr, u32 *data)
+{
+	xgene_serdes_rd(csr_base,
+			SM_PCIE_X8_SDS_CSR_REGS_PCIE_SDS_IND_CMD_REG_ADDR,
+			SM_PCIE_X8_SDS_CSR_REGS_PCIE_SDS_IND_RDATA_REG_ADDR,
+			addr, data);
+	PHYCSRDEBUG("PCIE SDS RD addr 0x%X value 0x%08X", addr, *data);
+}
+
+static void xgene_sds_pcie_toggle1to0(void *csr_base, u32 addr, u32 bits,
+				      u32 delayus)
+{
+	u32 val;
+	xgene_sds_pcie_rd(csr_base, addr, &val);
+	val |= bits;
+	xgene_sds_pcie_wr(csr_base, addr, val);
+	if (delayus > 0)	/* Allow Serdes to get reflected */
+		xgene_ahci_delayus(delayus);
+	xgene_sds_pcie_rd(csr_base, addr, &val);
+	val &= ~bits;
+	xgene_sds_pcie_wr(csr_base, addr, val);
+}
+
+static int xgene_serdes_cal_rdy_check(void *csr_serdes,
+				      void (*serdes_rd) (void *, u32, u32 *),
+				      void (*serdes_wr) (void *, u32, u32),
+				      void (*serdes_toggle1to0) (void *, u32,
+								 u32, u32))
+{
+	int loopcount;
+	u32 val;
+
+	/* TERM CALIBRATION CH0 */
+	serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG17_ADDR, &val);
+	val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x12);
+	val = CMU_REG17_RESERVED_7_SET(val, 0x0);
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG17_ADDR, val);
+	serdes_toggle1to0(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG17_ADDR,
+			  CMU_REG17_PVT_TERM_MAN_ENA_MASK, 0);
+	/* DOWN CALIBRATION CH0 */
+	serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG17_ADDR, &val);
+	val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x26);
+	val = CMU_REG17_RESERVED_7_SET(val, 0x0);
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG17_ADDR, val);
+	serdes_toggle1to0(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG16_ADDR,
+			  CMU_REG16_PVT_DN_MAN_ENA_MASK, 0);
+	/* UP CALIBRATION CH0 */
+	serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG17_ADDR, &val);
+	val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x28);
+	val = CMU_REG17_RESERVED_7_SET(val, 0x0);
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG17_ADDR, val);
+	serdes_toggle1to0(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG16_ADDR,
+			  CMU_REG16_PVT_UP_MAN_ENA_MASK, 0);
+
+	/* Check for PLL calibration for 1ms */
+	loopcount = 10;
+	do {
+		serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG7_ADDR, &val);
+		if (CMU_REG7_PLL_CALIB_DONE_RD(val))
+			return 0;
+		xgene_ahci_delayus(222); /* Allow Serdes to get reflected */
+	} while (!CMU_REG7_PLL_CALIB_DONE_RD(val) && --loopcount > 0);
+
+	return -1;
+}
+
+/* SATA port 0 - 3 PLL initialization */
+static int xgene_serdes_macro_cal_rdy_chk(struct xgene_ahci_context *ctx)
+{
+	void *csr_serdes = ctx->csr_base + SATA_SERDES_OFFSET;
+	u32 val;
+
+	xgene_serdes_cal_rdy_check(csr_serdes, xgene_sds_rd, xgene_sds_wr,
+				   xgene_sds_toggle1to0);
+
+	/* Check if PLL calibration complete sucessfully */
+	xgene_sds_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG7_ADDR, &val);
+	if (CMU_REG7_PLL_CALIB_DONE_RD(val) == 0x1)
+		PHYDEBUG("CLKMACRO PLL calibration done");
+	/* Check for VCO FAIL */
+	if (CMU_REG7_VCO_CAL_FAIL_RD(val) == 0x0) {
+		PHYDEBUG("CLKMACRO VCO calibration successful");
+		return 0;
+	}
+	/* Assert SDS reset for recall calibration if required */
+	xgene_ahci_in32(csr_serdes + SATA_ENET_CLK_MACRO_REG_ADDR, &val);
+	xgene_ahci_out32(csr_serdes + SATA_ENET_CLK_MACRO_REG_ADDR, val);
+	PHYERROR("CLKMACRO calibration failed due to VCO failure");
+	return -1;
+}
+
+/* SATA port 0 - 3 force power down VCO */
+static void xgene_serdes_macro_pdwn_force_vco(struct xgene_ahci_context *ctx)
+{
+	xgene_sds_toggle1to0(ctx->csr_base + SATA_SERDES_OFFSET,
+			     KC_CLKMACRO_CMU_REGS_CMU_REG0_ADDR,
+			     CMU_REG0_PDOWN_MASK, 1000);
+	xgene_sds_toggle1to0(ctx->csr_base + SATA_SERDES_OFFSET,
+			     KC_CLKMACRO_CMU_REGS_CMU_REG32_ADDR,
+			     CMU_REG32_FORCE_VCOCAL_START_MASK, 0);
+}
+
+/* SATA port 4 - 5 PLL initialization */
+static int xgene_serdes_sata45_macro_cal_rdy_chk(struct xgene_ahci_context *ctx)
+{
+	void *pcie_base = ctx->pcie_base;
+	u32 val;
+
+	xgene_serdes_cal_rdy_check(pcie_base, xgene_sds_pcie_rd,
+				   xgene_sds_pcie_wr,
+				   xgene_sds_pcie_toggle1to0);
+
+	/* PLL Calibration DONE */
+	xgene_sds_pcie_rd(pcie_base, KC_CLKMACRO_CMU_REGS_CMU_REG7_ADDR, &val);
+	if (CMU_REG7_PLL_CALIB_DONE_RD(val) == 0x1)
+		PHYDEBUG("CLKMACRO PLL CALIB done");
+	/* Check for VCO FAIL */
+	if (CMU_REG7_VCO_CAL_FAIL_RD(val) == 0x0) {
+		PHYDEBUG("CLKMACRO CALIB successful");
+		return 0;
+	}
+	PHYERROR("CLKMACRO CALIB failed due to VCO failure");
+	return -1;
+}
+
+static int xgene_serdes_macro_cfg(void *csr_serdes,
+				  void (*serdes_rd) (void *, u32, u32 *),
+				  void (*serdes_wr) (void *, u32, u32))
+{
+	u32 val;
+
+	serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG34_ADDR, &val);
+	val = CMU_REG34_VCO_CAL_VTH_LO_MAX_SET(val, 0x7);
+	val = CMU_REG34_VCO_CAL_VTH_HI_MAX_SET(val, 0xd);
+	val = CMU_REG34_VCO_CAL_VTH_LO_MIN_SET(val, 0x2);
+	val = CMU_REG34_VCO_CAL_VTH_HI_MIN_SET(val, 0x8);
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG34_ADDR, val);
+	serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG0_ADDR, &val);
+	val = CMU_REG0_CAL_COUNT_RESOL_SET(val, 0x4);
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG0_ADDR, val);
+	/* CMU_REG1 */
+	serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG1_ADDR, &val);
+	val = CMU_REG1_PLL_CP_SET(val, 0x1);
+	val = CMU_REG1_PLL_CP_SEL_SET(val, 0x5);
+	val = CMU_REG1_PLL_MANUALCAL_SET(val, 0x0);
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG1_ADDR, val);
+	/* CMU_REG2 */
+	serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG2_ADDR, &val);
+	val = CMU_REG2_PLL_LFRES_SET(val, 0xa);
+	val = CMU_REG2_PLL_FBDIV_SET(val, 0x27);	/* 100Mhz refclk */
+	val = CMU_REG2_PLL_FBDIV_SET(val, 0x4f);	/* 50Mhz refclk */
+	val = CMU_REG2_PLL_REFDIV_SET(val, 0x1);
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG2_ADDR, val);
+	/* CMU_REG3 */
+	serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG3_ADDR, &val);
+	val = CMU_REG3_VCOVARSEL_SET(val, 0xf);
+	val = CMU_REG3_VCO_MOMSEL_INIT_SET(val, 0x10);
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG3_ADDR, val);
+	/* CMU_REG26  */
+	serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG26_ADDR, &val);
+	val = CMU_REG26_FORCE_PLL_LOCK_SET(val, 0x0);
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG26_ADDR, val);
+	/* CMU_REG5 */
+	serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG5_ADDR, &val);
+	val = CMU_REG5_PLL_LFSMCAP_SET(val, 0x3);
+	val = CMU_REG5_PLL_LFCAP_SET(val, 0x3);
+	val = CMU_REG5_PLL_LOCK_RESOLUTION_SET(val, 0x7);
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG5_ADDR, val);
+	/* CMU_reg6 */
+	serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG6_ADDR, &val);
+	val = CMU_REG6_PLL_VREGTRIM_SET(val, 0x0);
+	val = CMU_REG6_MAN_PVT_CAL_SET(val, 0x1);
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG6_ADDR, val);
+	/* CMU_reg16 */
+	serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG16_ADDR, &val);
+	val = CMU_REG16_CALIBRATION_DONE_OVERRIDE_SET(val, 0x1);
+	val = CMU_REG16_BYPASS_PLL_LOCK_SET(val, 0x1);
+	val = CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(val, 0x4);
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG16_ADDR, val);
+	/* CMU_reg30 */
+	serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG30_ADDR, &val);
+	val = CMU_REG30_PCIE_MODE_SET(val, 0x0);
+	val = CMU_REG30_LOCK_COUNT_SET(val, 0x3);
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG30_ADDR, val);
+	/* CMU reg31 */
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG31_ADDR, 0xF);
+	/* CMU_reg32 */
+	serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG32_ADDR, &val);
+	val = CMU_REG32_PVT_CAL_WAIT_SEL_SET(val, 0x3);
+	val = CMU_REG32_IREF_ADJ_SET(val, 0x3);
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG32_ADDR, val);
+	/* CMU_reg34 */
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG34_ADDR, 0x8d27);
+	/* CMU_reg37 */
+	serdes_rd(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG37_ADDR, &val);
+	serdes_wr(csr_serdes, KC_CLKMACRO_CMU_REGS_CMU_REG37_ADDR, 0xF00F);
+
+	return 0;
+}
+
+/* SATA port 0 - 3 macro configuration */
+static int xgene_serdes_sata_macro_cfg(struct xgene_ahci_context *ctx)
+{
+	void *csr_serdes = ctx->csr_base + SATA_SERDES_OFFSET;
+	int calib_loop_count = 0;
+	u32 val;
+
+	xgene_ahci_in32(csr_serdes + SATA_ENET_CLK_MACRO_REG_ADDR, &val);
+	val = I_RESET_B_SET(val, 0x0);
+	val = I_PLL_FBDIV_SET(val, 0x27);
+	val = I_CUSTOMEROV_SET(val, 0x0);
+	xgene_ahci_out32(csr_serdes + SATA_ENET_CLK_MACRO_REG_ADDR, val);
+
+	xgene_serdes_macro_cfg(csr_serdes, xgene_sds_rd, xgene_sds_wr);
+
+	xgene_ahci_in32(csr_serdes + SATA_ENET_CLK_MACRO_REG_ADDR, &val);
+	val = I_RESET_B_SET(val, 0x1);
+	val = I_CUSTOMEROV_SET(val, 0x0);
+	xgene_ahci_out32(csr_serdes + SATA_ENET_CLK_MACRO_REG_ADDR, val);
+
+	xgene_ahci_delayus(8000);	/* Allow serdes to get reflected */
+	while (++calib_loop_count <= 5) {
+		if (xgene_serdes_macro_cal_rdy_chk(ctx) == 0)
+			break;
+		xgene_serdes_macro_pdwn_force_vco(ctx);
+	}
+	if (calib_loop_count > 5)
+		return -1;
+	xgene_ahci_in32(csr_serdes + SATA_ENET_CLK_MACRO_REG_ADDR, &val);
+	PHYDEBUG("PLL CLKMACRO %sLOOKED...", O_PLL_LOCK_RD(val) ? "" : "UN");
+	PHYDEBUG("PLL CLKMACRO %sREADY...", O_PLL_READY_RD(val) ? "" : "NOT");
+
+	return 0;
+}
+
+/* SATA port 4 - 5 force power down VCO */
+static void xgene_serdes_sata45_macro_pdwn_force_vco(struct xgene_ahci_context
+						     *ctx)
+{
+	xgene_sds_pcie_toggle1to0(ctx->pcie_base,
+				  KC_CLKMACRO_CMU_REGS_CMU_REG0_ADDR,
+				  CMU_REG0_PDOWN_MASK, 1000);
+	xgene_sds_pcie_toggle1to0(ctx->pcie_base,
+				  KC_CLKMACRO_CMU_REGS_CMU_REG32_ADDR,
+				  CMU_REG32_FORCE_VCOCAL_START_MASK, 0);
+}
+
+static void xgene_serdes_sata45_cfg_internal_clk(struct xgene_ahci_context *ctx)
+{
+	void *pcie_base = ctx->pcie_base;
+
+	xgene_ahci_out32_flush(pcie_base + SM_PCIE_CLKRST_CSR_PCIE_CLKEN_ADDR,
+			       0xff);
+	xgene_ahci_out32_flush(pcie_base + SM_PCIE_CLKRST_CSR_PCIE_SRST_ADDR,
+			       0x00);
+}
+
+void xgene_serdes_sata45_reset_cmos(struct xgene_ahci_context *ctx)
+{
+	void *pcie_base = ctx->pcie_base;
+
+	xgene_ahci_out32(pcie_base + SM_PCIE_CLKRST_CSR_PCIE_CLKEN_ADDR, 0x00);
+	xgene_ahci_out32(pcie_base + SM_PCIE_CLKRST_CSR_PCIE_SRST_ADDR, 0xff);
+}
+
+/* SATA port 4 - 5 macro configuration */
+static int xgene_serdes_sata45_macro_cfg(struct xgene_ahci_context *ctx)
+{
+	void *pcie_base = ctx->pcie_base;
+	int calib_loop_count;
+	u32 val;
+
+	xgene_serdes_sata45_cfg_internal_clk(ctx);
+
+	xgene_ahci_in32(pcie_base +
+			SM_PCIE_X8_SDS_CSR_REGS_PCIE_CLK_MACRO_REG_ADDR, &val);
+	val = PCIE_CLK_MACRO_REG_I_RESET_B_SET(val, 0x0);
+	val = PCIE_CLK_MACRO_REG_I_CUSTOMEROV_SET(val, 0x0);
+	xgene_ahci_out32(pcie_base +
+			 SM_PCIE_X8_SDS_CSR_REGS_PCIE_CLK_MACRO_REG_ADDR, val);
+	xgene_ahci_in32(pcie_base +
+			SM_PCIE_X8_SDS_CSR_REGS_PCIE_CLK_MACRO_REG_ADDR, &val);
+
+	xgene_serdes_macro_cfg(pcie_base, xgene_sds_pcie_rd, xgene_sds_pcie_wr);
+
+	xgene_ahci_in32(pcie_base +
+			SM_PCIE_X8_SDS_CSR_REGS_PCIE_CLK_MACRO_REG_ADDR, &val);
+	val = PCIE_CLK_MACRO_REG_I_RESET_B_SET(val, 0x1);
+	val = PCIE_CLK_MACRO_REG_I_CUSTOMEROV_SET(val, 0x0);
+	xgene_ahci_out32(pcie_base +
+			 SM_PCIE_X8_SDS_CSR_REGS_PCIE_CLK_MACRO_REG_ADDR, val);
+
+	xgene_ahci_delayus(8000);	/* Allow Serdes to get reflected */
+	calib_loop_count = 5;
+	do {
+		if (xgene_serdes_sata45_macro_cal_rdy_chk(ctx) == 0)
+			break;
+		xgene_serdes_sata45_macro_pdwn_force_vco(ctx);
+		xgene_ahci_delayus(8000); /* Allow Serdes to get reflected */
+	} while (--calib_loop_count > 0);
+	if (calib_loop_count <= 0)
+		return -1;
+	xgene_ahci_in32(pcie_base +
+			SM_PCIE_X8_SDS_CSR_REGS_PCIE_CLK_MACRO_REG_ADDR, &val);
+	PHYDEBUG("PLL CLKMACRO %sLOOKED...",
+		 PCIE_CLK_MACRO_REG_O_PLL_LOCK_RD(val) ? "" : "UN");
+	PHYDEBUG("PLL CLKMACRO %sREADY...",
+		 PCIE_CLK_MACRO_REG_O_PLL_READY_RD(val) ? "" : "NOT ");
+
+	return 0;
+}
+
+static void xgene_serdes_clk_rst_pre(struct xgene_ahci_context *ctx)
+{
+	void *clkcsr_base = ctx->csr_base + SATA_CLK_OFFSET;
+	u32 val;
+
+	PHYDEBUG("SATA%d controller clock enable", ctx->cid);
+	/* disable all reset */
+	xgene_ahci_out32_flush(clkcsr_base + SATASRESETREG_ADDR, 0x00);
+
+	/* Enable all resets */
+	xgene_ahci_out32_flush(clkcsr_base + SATASRESETREG_ADDR, 0xff);
+
+	/* Disable all clks */
+	xgene_ahci_out32_flush(clkcsr_base + SATACLKENREG_ADDR, 0x00);
+
+	/* Enable all clks */
+	xgene_ahci_out32_flush(clkcsr_base + SATACLKENREG_ADDR, 0xf9);
+
+	/* Get out of reset for:
+	 *  SDS, CSR
+	 *  CORE & MEM are still reset
+	 */
+	xgene_ahci_in32(clkcsr_base + SATASRESETREG_ADDR, &val);
+	if (SATA_MEM_RESET_RD(val) == 1) {
+		val &= ~(SATA_CSR_RESET_MASK | SATA_SDS_RESET_MASK);
+		val |= SATA_CORE_RESET_MASK | SATA_PCLK_RESET_MASK |
+		    SATA_PMCLK_RESET_MASK | SATA_MEM_RESET_MASK;
+	}
+	xgene_ahci_out32_flush(clkcsr_base + SATASRESETREG_ADDR, val);
+}
+
+void xgene_ahci_serdes_reset_rxa_rxd(struct xgene_ahci_context *ctx, int chan)
+{
+	void *csr_base = ctx->csr_base + SATA_SERDES_OFFSET;
+
+	xgene_sds_clrbits(csr_base,
+			  KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG7_ADDR +
+			  chan * 0x200, CH0_RXTX_REG7_RESETB_RXD_MASK);
+	xgene_sds_clrbits(csr_base,
+			  KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG7_ADDR +
+			  chan * 0x200, CH0_RXTX_REG7_RESETB_RXA_MASK);
+	xgene_sds_setbits(csr_base,
+			  KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG7_ADDR +
+			  chan * 0x200, CH0_RXTX_REG7_RESETB_RXA_MASK);
+	xgene_sds_setbits(csr_base,
+			  KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG7_ADDR +
+			  chan * 0x200, CH0_RXTX_REG7_RESETB_RXD_MASK);
+}
+
+static void xgene_serdes_reset_pclk(struct xgene_ahci_context *ctx)
+{
+	void *clkcsr_base = ctx->csr_base + SATA_CLK_OFFSET;
+	u32 val;
+
+	xgene_ahci_in32(clkcsr_base + SATASRESETREG_ADDR, &val);
+	val &= ~SATA_PCLK_RESET_MASK;
+	xgene_ahci_out32(clkcsr_base + SATASRESETREG_ADDR, val);
+}
+
+static void xgene_serdes_reset_sds_pmclk_core(struct xgene_ahci_context *ctx)
+{
+	void *clkcsr_base = ctx->csr_base + SATA_CLK_OFFSET;
+	u32 val;
+
+	xgene_ahci_in32(clkcsr_base + SATASRESETREG_ADDR, &val);
+	val &= ~(SATA_CORE_RESET_MASK |
+		 SATA_PMCLK_RESET_MASK | SATA_SDS_RESET_MASK);
+	xgene_ahci_out32(clkcsr_base + SATASRESETREG_ADDR, val);
+}
+
+void xgene_ahci_serdes_force_lat_summer_cal(struct xgene_ahci_context *ctx,
+					    int channel)
+{
+	void *csr_base = ctx->csr_base + SATA_SERDES_OFFSET;
+	u32 os = channel * 0x200;
+	int i;
+	struct {
+		u32 reg;
+		u32 val;
+	} serdes_reg[] = {
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG38_ADDR, 0x0},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG39_ADDR, 0xff00},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG40_ADDR, 0xffff},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG41_ADDR, 0xffff},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG42_ADDR, 0xffff},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG43_ADDR, 0xffff},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG44_ADDR, 0xffff},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG45_ADDR, 0xffff},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG46_ADDR, 0xffff},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG47_ADDR, 0xfffc},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG48_ADDR, 0x0},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG49_ADDR, 0x0},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG50_ADDR, 0x0},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG51_ADDR, 0x0},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG52_ADDR, 0x0},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG53_ADDR, 0x0},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG54_ADDR, 0x0},
+		{KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG55_ADDR, 0x0},
+		{0, 0x0},
+	};
+
+	/* SUMMER CALIBRATION CH0/CH1 */
+	/* SUMMER calib toggle CHX */
+	xgene_sds_toggle1to0(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG127_ADDR + os,
+			     CH0_RXTX_REG127_FORCE_SUM_CAL_START_MASK, 0);
+	/* latch calib toggle CHX */
+	xgene_sds_toggle1to0(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG127_ADDR + os,
+			     CH0_RXTX_REG127_FORCE_LAT_CAL_START_MASK, 0);
+	/* CHX */
+	xgene_sds_wr(csr_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG28_ADDR + os, 0x7);
+	xgene_sds_wr(csr_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG31_ADDR + os, 0x7e00);
+
+	xgene_sds_clrbits(csr_base,
+			  KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG4_ADDR + os,
+			  CH0_RXTX_REG4_TX_LOOPBACK_BUF_EN_MASK);
+	xgene_sds_clrbits(csr_base,
+			  KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG7_ADDR + os,
+			  CH0_RXTX_REG7_LOOP_BACK_ENA_CTLE_MASK);
+
+	/* RXTX_REG38-55 */
+	for (i = 0; serdes_reg[i].reg != 0; i++)
+		xgene_sds_wr(csr_base, serdes_reg[i].reg + os,
+			     serdes_reg[i].val);
+}
+
+void xgene_serdes_force_lat_summer_cal_get_avg(struct xgene_ahci_context *ctx,
+					       int chan)
+{
+	void *csr_serdes_base = ctx->csr_base + SATA_SERDES_OFFSET;
+	u32 os = chan * 0x200;
+
+	/* SUMMer calib toggle */
+	xgene_sds_toggle1to0(csr_serdes_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG127_ADDR + os,
+			     CH0_RXTX_REG127_FORCE_SUM_CAL_START_MASK, 0);
+	xgene_sds_toggle1to0(csr_serdes_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG127_ADDR + os,
+			     CH0_RXTX_REG127_FORCE_LAT_CAL_START_MASK, 0);
+	xgene_sds_clrbits(csr_serdes_base,
+			  KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG4_ADDR + os,
+			  CH0_RXTX_REG4_TX_LOOPBACK_BUF_EN_MASK);
+	xgene_sds_clrbits(csr_serdes_base,
+			  KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG7_ADDR + os,
+			  CH0_RXTX_REG7_LOOP_BACK_ENA_CTLE_MASK);
+
+	/* removing loopback after calibration cycle */
+	xgene_sds_clrbits(csr_serdes_base,
+			  KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG4_ADDR + os,
+			  CH0_RXTX_REG4_TX_LOOPBACK_BUF_EN_MASK);
+	xgene_sds_clrbits(csr_serdes_base,
+			  KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG7_ADDR + os,
+			  CH0_RXTX_REG7_LOOP_BACK_ENA_CTLE_MASK);
+	/* RXTX_REG38 */
+	xgene_sds_wr(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG38_ADDR + os, 0x0);
+}
+
+int xgene_serdes_get_avg(int accum, int samples)
+{
+	return (accum + (samples / 2)) / samples;
+}
+
+static void xgene_serdes_reset_rxd(struct xgene_ahci_context *ctx, int channel)
+{
+	void *csr_base = ctx->csr_base + SATA_SERDES_OFFSET;
+
+	xgene_sds_clrbits(csr_base,
+			  KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG7_ADDR +
+			  channel * 0x200, CH0_RXTX_REG7_RESETB_RXD_MASK);
+	xgene_sds_setbits(csr_base,
+			  KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG7_ADDR +
+			  channel * 0x200, CH0_RXTX_REG7_RESETB_RXD_MASK);
+}
+
+void xgene_ahci_serdes_gen_avg_val(struct xgene_ahci_context *ctx, int channel)
+{
+	void *csr_serdes_base = ctx->csr_base + SATA_SERDES_OFFSET;
+	int avg_loop = 10;
+	int MAX_LOOP = 10;
+	int lat_do = 0, lat_xo = 0, lat_eo = 0, lat_so = 0;
+	int lat_de = 0, lat_xe = 0, lat_ee = 0, lat_se = 0;
+	int sum_cal = 0;
+	int lat_do_itr = 0, lat_xo_itr = 0, lat_eo_itr = 0, lat_so_itr = 0;
+	int lat_de_itr = 0, lat_xe_itr = 0, lat_ee_itr = 0, lat_se_itr = 0;
+	int sum_cal_itr = 0;
+	int fail_even = 0;
+	int fail_odd = 0;
+	u32 val;
+	u32 os;
+
+	PHYDEBUG("Generating average calibration value for port %d", channel);
+
+	os = channel * 0x200;
+
+	/* Enable RX Hi-Z termination enable */
+	xgene_sds_setbits(csr_serdes_base,
+			  KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG12_ADDR + os,
+			  CH0_RXTX_REG12_RX_DET_TERM_ENABLE_MASK);
+	/* Turn off DFE */
+	xgene_sds_wr(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG28_ADDR + os, 0x0000);
+	/* DFE Presets to zero */
+	xgene_sds_wr(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG31_ADDR + os, 0x0000);
+
+	while (avg_loop > 0) {
+		xgene_ahci_serdes_force_lat_summer_cal(ctx, channel);
+
+		xgene_sds_rd(csr_serdes_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG21_ADDR + os,
+			     &val);
+		lat_do_itr = CH0_RXTX_REG21_DO_LATCH_CALOUT_RD(val);
+		lat_xo_itr = CH0_RXTX_REG21_XO_LATCH_CALOUT_RD(val);
+		fail_odd = CH0_RXTX_REG21_LATCH_CAL_FAIL_ODD_RD(val);
+
+		xgene_sds_rd(csr_serdes_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG22_ADDR + os,
+			     &val);
+		lat_eo_itr = CH0_RXTX_REG22_EO_LATCH_CALOUT_RD(val);
+		lat_so_itr = CH0_RXTX_REG22_SO_LATCH_CALOUT_RD(val);
+		fail_even = CH0_RXTX_REG22_LATCH_CAL_FAIL_EVEN_RD(val);
+
+		xgene_sds_rd(csr_serdes_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG23_ADDR + os,
+			     &val);
+		lat_de_itr = CH0_RXTX_REG23_DE_LATCH_CALOUT_RD(val);
+		lat_xe_itr = CH0_RXTX_REG23_XE_LATCH_CALOUT_RD(val);
+		xgene_sds_rd(csr_serdes_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG24_ADDR + os,
+			     &val);
+		lat_ee_itr = CH0_RXTX_REG24_EE_LATCH_CALOUT_RD(val);
+		lat_se_itr = CH0_RXTX_REG24_SE_LATCH_CALOUT_RD(val);
+
+		xgene_sds_rd(csr_serdes_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG121_ADDR + os,
+			     &val);
+		sum_cal_itr = CH0_RXTX_REG121_SUMOS_CAL_CODE_RD(val);
+
+		if ((fail_even == 0 || fail_even == 1) &&
+		    (fail_odd == 0 || fail_odd == 1)) {
+			lat_do += lat_do_itr;
+			lat_xo += lat_xo_itr;
+			lat_eo += lat_eo_itr;
+			lat_so += lat_so_itr;
+			lat_de += lat_de_itr;
+			lat_xe += lat_xe_itr;
+			lat_ee += lat_ee_itr;
+			lat_se += lat_se_itr;
+			sum_cal += sum_cal_itr;
+
+			PHYDEBUG("Interation Value: %d", avg_loop);
+			PHYDEBUG("DO 0x%x XO 0x%x EO 0x%x SO 0x%x", lat_do_itr,
+				 lat_xo_itr, lat_eo_itr, lat_so_itr);
+			PHYDEBUG("DE 0x%x XE 0x%x EE 0x%x SE 0x%x", lat_de_itr,
+				 lat_xe_itr, lat_ee_itr, lat_se_itr);
+			PHYDEBUG("sum_cal 0x%x", sum_cal_itr);
+			avg_loop--;
+		} else {
+			PHYDEBUG("Interation Failed %d", avg_loop);
+		}
+		xgene_serdes_reset_rxd(ctx, channel);
+	}
+
+	/* Update with Average Value */
+	xgene_sds_rd(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG127_ADDR + os, &val);
+	val = CH0_RXTX_REG127_DO_LATCH_MANCAL_SET(val,
+		xgene_serdes_get_avg(lat_do, MAX_LOOP));
+	val = CH0_RXTX_REG127_XO_LATCH_MANCAL_SET(val,
+		xgene_serdes_get_avg(lat_xo, MAX_LOOP));
+	xgene_sds_wr(csr_serdes_base,
+		KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG127_ADDR + os, val);
+
+	xgene_sds_rd(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG128_ADDR + os, &val);
+	val = CH0_RXTX_REG128_EO_LATCH_MANCAL_SET(val,
+		xgene_serdes_get_avg(lat_eo, MAX_LOOP));
+	val = CH0_RXTX_REG128_SO_LATCH_MANCAL_SET(val,
+		xgene_serdes_get_avg(lat_so, MAX_LOOP));
+	xgene_sds_wr(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG128_ADDR + os, val);
+	xgene_sds_rd(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG129_ADDR + os, &val);
+	val = CH0_RXTX_REG129_DE_LATCH_MANCAL_SET(val,
+		xgene_serdes_get_avg(lat_de, MAX_LOOP));
+	val = CH0_RXTX_REG129_XE_LATCH_MANCAL_SET(val,
+		xgene_serdes_get_avg(lat_xe, MAX_LOOP));
+	xgene_sds_wr(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG129_ADDR + os, val);
+
+	xgene_sds_rd(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG130_ADDR + os, &val);
+	val = CH0_RXTX_REG130_EE_LATCH_MANCAL_SET(val,
+		xgene_serdes_get_avg(lat_ee, MAX_LOOP));
+	val = CH0_RXTX_REG130_SE_LATCH_MANCAL_SET(val,
+		xgene_serdes_get_avg(lat_se, MAX_LOOP));
+	xgene_sds_wr(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG130_ADDR + os, val);
+	/* Summer Calibration Value */
+	xgene_sds_rd(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG14_ADDR + os, &val);
+	val = CH0_RXTX_REG14_CLTE_LATCAL_MAN_PROG_SET(val,
+		xgene_serdes_get_avg(sum_cal, MAX_LOOP));
+	xgene_sds_wr(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG14_ADDR + os, val);
+
+	PHYDEBUG("Average Value:");
+	PHYDEBUG("DO 0x%x XO 0x%x EO 0x%x SO 0x%x",
+		 xgene_serdes_get_avg(lat_do, MAX_LOOP),
+		 xgene_serdes_get_avg(lat_xo, MAX_LOOP),
+		 xgene_serdes_get_avg(lat_eo, MAX_LOOP),
+		 xgene_serdes_get_avg(lat_so, MAX_LOOP));
+	PHYDEBUG("DE 0x%x XE 0x%x EE 0x%x SE 0x%x",
+		 xgene_serdes_get_avg(lat_de, MAX_LOOP),
+		 xgene_serdes_get_avg(lat_xe, MAX_LOOP),
+		 xgene_serdes_get_avg(lat_ee, MAX_LOOP),
+		 xgene_serdes_get_avg(lat_se, MAX_LOOP));
+	PHYDEBUG("sum_cal 0x%x", xgene_serdes_get_avg(sum_cal, MAX_LOOP));
+
+	/* Manual Summer Calibration */
+	xgene_sds_rd(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG14_ADDR + os, &val);
+	val = CH0_RXTX_REG14_CTLE_LATCAL_MAN_ENA_SET(val, 0x1);
+	xgene_sds_wr(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG14_ADDR + os, val);
+
+	PHYDEBUG("Manual Summer calibration enabled");
+	xgene_ahci_delayus(122);	/* Allow serdes to get reflected */
+
+	/* Manual Latch Calibration */
+	xgene_sds_rd(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG127_ADDR + os, &val);
+	val = CH0_RXTX_REG127_LATCH_MAN_CAL_ENA_SET(val, 0x1);
+	PHYDEBUG("Manual Latch Calibration Enabled");
+	xgene_sds_wr(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG127_ADDR + os, val);
+	xgene_ahci_delayus(122);	/* Allow serdes to get reflected */
+
+	/* Disable RX Hi-Z termination enable */
+	xgene_sds_rd(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG12_ADDR + os, &val);
+	val = CH0_RXTX_REG12_RX_DET_TERM_ENABLE_SET(val, 0);
+	xgene_sds_wr(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG12_ADDR + os, val);
+
+	/* Turn on DFE */
+	xgene_sds_wr(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG28_ADDR + os, 0x0007);
+
+	/* DFE Presets to 0 */
+	xgene_sds_wr(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG31_ADDR + os, 0x7e00);
+}
+
+static int xgene_serdes_host_sata_select(struct xgene_ahci_context *ctx)
+{
+	void *muxcsr_base = ctx->csr_base + SATA_ETH_MUX_OFFSET;
+	u32 val;
+
+	PHYDEBUG("SATA%d select SATA MUX", ctx->cid);
+	xgene_ahci_in32(muxcsr_base + SATA_ENET_CONFIG_REG_ADDR, &val);
+	val &= ~CFG_SATA_ENET_SELECT_MASK;
+	xgene_ahci_out32(muxcsr_base + SATA_ENET_CONFIG_REG_ADDR, val);
+	xgene_ahci_in32(muxcsr_base + SATA_ENET_CONFIG_REG_ADDR, &val);
+	return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0;
+}
+
+static void xgene_serdes_validation_CMU_cfg(struct xgene_ahci_context *ctx)
+{
+	void *csr_base = ctx->csr_base + SATA_SERDES_OFFSET;
+	u32 val;
+
+	xgene_sds_rd(csr_base, KC_SERDES_CMU_REGS_CMU_REG0_ADDR, &val);
+	val = CMU_REG0_CAL_COUNT_RESOL_SET(val, 0x4);
+	xgene_sds_wr(csr_base, KC_SERDES_CMU_REGS_CMU_REG0_ADDR, val);
+
+	xgene_sds_rd(csr_base, KC_SERDES_CMU_REGS_CMU_REG1_ADDR, &val);
+	val = CMU_REG1_PLL_CP_SET(val, 0x1);
+	val = CMU_REG1_PLL_CP_SEL_SET(val, 0x5);
+	val = CMU_REG1_PLL_MANUALCAL_SET(val, 0x0);
+	xgene_sds_wr(csr_base, KC_SERDES_CMU_REGS_CMU_REG1_ADDR, val);
+
+	xgene_sds_rd(csr_base, KC_SERDES_CMU_REGS_CMU_REG2_ADDR, &val);
+	val = CMU_REG2_PLL_LFRES_SET(val, 0xa);
+	val = CMU_REG2_PLL_FBDIV_SET(val, FBDIV_VAL);
+	val = CMU_REG2_PLL_REFDIV_SET(val, REFDIV_VAL);
+	xgene_sds_wr(csr_base, KC_SERDES_CMU_REGS_CMU_REG2_ADDR, val);
+
+	xgene_sds_rd(csr_base, KC_SERDES_CMU_REGS_CMU_REG3_ADDR, &val);
+	val = CMU_REG3_VCOVARSEL_SET(val, 0xF);
+	val = CMU_REG3_VCO_MOMSEL_INIT_SET(val, 0x15);
+	val = CMU_REG3_VCO_MANMOMSEL_SET(val, 0x15);
+	xgene_sds_wr(csr_base, KC_SERDES_CMU_REGS_CMU_REG3_ADDR, val);
+
+	xgene_sds_rd(csr_base, KC_SERDES_CMU_REGS_CMU_REG26_ADDR, &val);
+	val = CMU_REG26_FORCE_PLL_LOCK_SET(val, 0x0);
+	xgene_sds_wr(csr_base, KC_SERDES_CMU_REGS_CMU_REG26_ADDR, val);
+
+	xgene_sds_rd(csr_base, KC_SERDES_CMU_REGS_CMU_REG5_ADDR, &val);
+	val = CMU_REG5_PLL_LFSMCAP_SET(val, 0x3);
+	val = CMU_REG5_PLL_LFCAP_SET(val, 0x3);
+	if (xgene_ahci_is_A1())
+		val = CMU_REG5_PLL_LOCK_RESOLUTION_SET(val, 0x7);
+	else
+		val = CMU_REG5_PLL_LOCK_RESOLUTION_SET(val, 0x4);
+	xgene_sds_wr(csr_base, KC_SERDES_CMU_REGS_CMU_REG5_ADDR, val);
+
+	xgene_sds_rd(csr_base, KC_SERDES_CMU_REGS_CMU_REG6_ADDR, &val);
+	val = CMU_REG6_PLL_VREGTRIM_SET(val, 0x0);
+	val = CMU_REG6_MAN_PVT_CAL_SET(val, 0x1);
+	xgene_sds_wr(csr_base, KC_SERDES_CMU_REGS_CMU_REG6_ADDR, val);
+
+	xgene_sds_rd(csr_base, KC_SERDES_CMU_REGS_CMU_REG9_ADDR, &val);
+	val = CMU_REG9_TX_WORD_MODE_CH1_SET(val, 0x3);
+	val = CMU_REG9_TX_WORD_MODE_CH0_SET(val, 0x3);
+	val = CMU_REG9_PLL_POST_DIVBY2_SET(val, 0x1);
+	xgene_sds_wr(csr_base, KC_SERDES_CMU_REGS_CMU_REG9_ADDR, val);
+
+	xgene_sds_rd(csr_base, KC_SERDES_CMU_REGS_CMU_REG16_ADDR, &val);
+	val = CMU_REG16_CALIBRATION_DONE_OVERRIDE_SET(val, 0x1);
+	val = CMU_REG16_BYPASS_PLL_LOCK_SET(val, 0x1);
+	val = CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(val, 0x4);
+	xgene_sds_wr(csr_base, KC_SERDES_CMU_REGS_CMU_REG16_ADDR, val);
+
+	xgene_sds_rd(csr_base, KC_SERDES_CMU_REGS_CMU_REG30_ADDR, &val);
+	val = CMU_REG30_PCIE_MODE_SET(val, 0x0);
+	val = CMU_REG30_LOCK_COUNT_SET(val, 0x3);
+	xgene_sds_wr(csr_base, KC_SERDES_CMU_REGS_CMU_REG30_ADDR, val);
+
+	xgene_sds_wr(csr_base, KC_SERDES_CMU_REGS_CMU_REG31_ADDR, 0xF);
+
+	xgene_sds_rd(csr_base, KC_SERDES_CMU_REGS_CMU_REG32_ADDR, &val);
+	if (xgene_ahci_is_A1())
+		val |= 0x0006 | 0x0180;
+	val = CMU_REG32_PVT_CAL_WAIT_SEL_SET(val, 0x3);
+	val = CMU_REG32_IREF_ADJ_SET(val, 0x3);
+	xgene_sds_wr(csr_base, KC_SERDES_CMU_REGS_CMU_REG32_ADDR, val);
+
+	xgene_sds_wr(csr_base, KC_SERDES_CMU_REGS_CMU_REG34_ADDR, 0x8d27);
+
+	xgene_sds_wr(csr_base, KC_SERDES_CMU_REGS_CMU_REG37_ADDR, 0xF00F);
+}
+
+static void xgene_serdes_validation_rxtx_cfg(struct xgene_ahci_context *ctx,
+					     int gen_sel)
+{
+	void *csr_base = ctx->csr_base + SATA_SERDES_OFFSET;
+	u32 val;
+	u32 reg;
+	int i;
+	int chan;
+
+	for (chan = 0; chan < 2; chan++) {
+		u32 os = chan * 0x200;
+
+		if (xgene_ahci_is_A1()) {
+			xgene_sds_wr(csr_base,
+				     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG38_ADDR
+				     + os, 0x40);
+			xgene_sds_wr(csr_base,
+				     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG38_ADDR
+				     + os, 0x41);
+		}
+
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG147_ADDR + os,
+			     0x6);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG0_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG0_CTLE_EQ_HR_SET(val, 0x10);
+		val = CH0_RXTX_REG0_CTLE_EQ_QR_SET(val, 0x10);
+		val = CH0_RXTX_REG0_CTLE_EQ_FR_SET(val, 0x10);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG0_ADDR + os,
+			     val);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG1_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG1_RXACVCM_SET(val, 0x7);
+		if (xgene_ahci_is_A1())
+			val = CH0_RXTX_REG1_CTLE_EQ_SET(val, ctx->ctrl_eq_A1);
+		else
+			val = CH0_RXTX_REG1_CTLE_EQ_SET(val, ctx->ctrl_eq);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG1_ADDR + os,
+			     val);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG2_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG2_VTT_ENA_SET(val, 0x1);
+		val = CH0_RXTX_REG2_VTT_SEL_SET(val, 0x1);
+		val = CH0_RXTX_REG2_TX_FIFO_ENA_SET(val, 0x1);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG2_ADDR + os,
+			     val);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG4_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG4_TX_WORD_MODE_SET(val, 0x3);
+		if (xgene_ahci_is_A1())
+			val = CH1_RXTX_REG4_TX_LOOPBACK_BUF_EN_SET(val,
+					ctx->loopback_buf_en_A1);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG4_ADDR + os,
+			     val);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG5_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG5_TX_CN1_SET(val, 0x0);
+		val = CH0_RXTX_REG5_TX_CP1_SET(val, 0xF);
+		val = CH0_RXTX_REG5_TX_CN2_SET(val, 0x0);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG5_ADDR + os,
+			     val);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG6_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG6_TXAMP_CNTL_SET(val, 0xf);
+		val = CH0_RXTX_REG6_TXAMP_ENA_SET(val, 0x1);
+		val = CH0_RXTX_REG6_TX_IDLE_SET(val, 0x0);
+		val = CH0_RXTX_REG6_RX_BIST_RESYNC_SET(val, 0x0);
+		val = CH0_RXTX_REG6_RX_BIST_ERRCNT_RD_SET(val, 0x0);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG6_ADDR + os,
+			     val);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG7_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG7_BIST_ENA_RX_SET(val, 0x0);
+		if (xgene_ahci_is_A1())
+			val = CH0_RXTX_REG7_LOOP_BACK_ENA_CTLE_SET(val,
+					ctx->loopback_ena_ctle_A1);
+		val = CH0_RXTX_REG7_RX_WORD_MODE_SET(val, 0x3);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG7_ADDR + os,
+			     val);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG8_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG8_CDR_LOOP_ENA_SET(val, 0x1);
+		val = CH0_RXTX_REG8_CDR_BYPASS_RXLOS_SET(val, 0x0);
+		val = CH0_RXTX_REG8_SSC_ENABLE_SET(val, 0x1);
+		val = CH0_RXTX_REG8_SD_DISABLE_SET(val, 0x0);
+		val = CH0_RXTX_REG8_SD_VREF_SET(val, 0x4);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG8_ADDR + os,
+			     val);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG11_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG11_PHASE_ADJUST_LIMIT_SET(val, 0x0);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG11_ADDR + os,
+			     val);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG12_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG12_LATCH_OFF_ENA_SET(val, 0x1);
+		val = CH0_RXTX_REG12_SUMOS_ENABLE_SET(val, 0x0);
+		val = CH0_RXTX_REG12_RX_DET_TERM_ENABLE_SET(val, 0x0);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG12_ADDR + os,
+			     val);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG26_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG26_PERIOD_ERROR_LATCH_SET(val, 0x0);
+		val = CH0_RXTX_REG26_BLWC_ENA_SET(val, 0x1);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG26_ADDR + os,
+			     val);
+
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG28_ADDR + os,
+			     0x0);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG31_ADDR + os,
+			     0x0);
+
+		/* RXTX REG39-55 */
+		if (xgene_ahci_is_A1()) {
+			for (i = 0; i < 17; i++)
+				xgene_sds_wr(csr_base,
+				    KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG39_ADDR
+				    + os + i * 2, 0x0000);
+		}
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG61_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG61_ISCAN_INBERT_SET(val, 0x1);
+		if (xgene_ahci_is_A1())
+			val = CH0_RXTX_REG61_SPD_SEL_CDR_SET(val,
+					ctx->spd_sel_cdr_A1);
+		val = CH0_RXTX_REG61_LOADFREQ_SHIFT_SET(val, 0x0);
+		val = CH0_RXTX_REG61_EYE_COUNT_WIDTH_SEL_SET(val, 0x0);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG61_ADDR + os,
+			     val);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG62_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG62_PERIOD_H1_QLATCH_SET(val, 0x0);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG62_ADDR + os,
+			     val);
+
+		for (i = 0; i < 9; i++) {
+			reg = KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG81_ADDR +
+				os + i * 2;
+			xgene_sds_rd(csr_base, reg, &val);
+			val = CH0_RXTX_REG89_MU_TH7_SET(val, 0xe);
+			val = CH0_RXTX_REG89_MU_TH8_SET(val, 0xe);
+			val = CH0_RXTX_REG89_MU_TH9_SET(val, 0xe);
+			xgene_sds_wr(csr_base, reg, val);
+		}
+
+		for (i = 0; i < 3; i++) {
+			reg = KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG96_ADDR +
+				os + i * 2;
+			xgene_sds_rd(csr_base, reg, &val);
+			val = CH0_RXTX_REG96_MU_FREQ1_SET(val, 0x10);
+			val = CH0_RXTX_REG96_MU_FREQ2_SET(val, 0x10);
+			val = CH0_RXTX_REG96_MU_FREQ3_SET(val, 0x10);
+			xgene_sds_wr(csr_base, reg, val);
+		}
+
+		for (i = 0; i < 3; i++) {
+			reg = KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG99_ADDR +
+				os + i * 2;
+			xgene_sds_rd(csr_base, reg, &val);
+			val = CH0_RXTX_REG99_MU_PHASE1_SET(val, 0x7);
+			val = CH0_RXTX_REG99_MU_PHASE2_SET(val, 0x7);
+			val = CH0_RXTX_REG99_MU_PHASE3_SET(val, 0x7);
+			xgene_sds_wr(csr_base, reg, val);
+		}
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG102_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG102_FREQLOOP_LIMIT_SET(val, 0x0);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG102_ADDR + os,
+			     val);
+
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG114_ADDR + os,
+			     0xffe0);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG125_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG125_SIGN_PQ_SET(val, ctx->pq_sign);
+		if (xgene_ahci_is_A1())
+			val = CH0_RXTX_REG125_PQ_REG_SET(val, ctx->pq_A1);
+		else
+			val = CH0_RXTX_REG125_PQ_REG_SET(val, ctx->pq);
+		val = CH0_RXTX_REG125_PHZ_MANUAL_SET(val, 0x1);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG125_ADDR + os,
+			     val);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG127_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG127_LATCH_MAN_CAL_ENA_SET(val, 0x0);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG127_ADDR + os,
+			     val);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG128_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG128_LATCH_CAL_WAIT_SEL_SET(val, 0x3);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG128_ADDR + os,
+			     val);
+
+		xgene_sds_rd(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG145_ADDR + os,
+			     &val);
+		val = CH0_RXTX_REG145_RXDFE_CONFIG_SET(val, 0x3);
+		val = CH0_RXTX_REG145_TX_IDLE_SATA_SET(val, 0x0);
+		val = CH0_RXTX_REG145_RXES_ENA_SET(val, 0x1);
+		val = CH0_RXTX_REG145_RXVWES_LATENA_SET(val, 0x1);
+		xgene_sds_wr(csr_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG145_ADDR + os,
+			     val);
+
+		for (i = 0; i < 4; i++) {
+			reg = KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG148_ADDR +
+			    os + i * 2;
+			xgene_sds_wr(csr_base, reg, 0xFFFF);
+		}
+	}
+}
+
+static int xgene_serdes_cal_rdy_chk(struct xgene_ahci_context *ctx)
+{
+	void *csr_serdes = ctx->csr_base + SATA_SERDES_OFFSET;
+	int loopcount;
+	u32 val;
+
+	/* 4. relasase serdes main reset */
+	xgene_ahci_out32_flush(csr_serdes + SATA_ENET_SDS_RST_CTL_ADDR,
+			       0x000000DF);
+	xgene_ahci_delayus(8000);	/* Allow Serdes to get reflected */
+
+	/* TERM CALIBRATION KC_SERDES_CMU_REGS_CMU_REG17__ADDR */
+	/* TERM calibration for channel 0 */
+	xgene_sds_rd(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG17_ADDR, &val);
+	val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x12);
+	val = CMU_REG17_RESERVED_7_SET(val, 0x0);
+	xgene_sds_wr(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG17_ADDR, val);
+	xgene_sds_toggle1to0(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG17_ADDR,
+			     CMU_REG17_PVT_TERM_MAN_ENA_MASK, 0);
+	/* DOWN CALIBRATION for channel zero */
+	xgene_sds_rd(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG17_ADDR, &val);
+	val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x29);
+	val = CMU_REG17_RESERVED_7_SET(val, 0x0);
+	xgene_sds_wr(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG17_ADDR, val);
+	xgene_sds_toggle1to0(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG16_ADDR,
+			     CMU_REG16_PVT_DN_MAN_ENA_MASK, 0);
+	/* UP CALIBRATION for channel 0 */
+	xgene_sds_rd(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG17_ADDR, &val);
+	val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x28);
+	val = CMU_REG17_RESERVED_7_SET(val, 0x0);
+	xgene_sds_wr(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG17_ADDR, val);
+	xgene_sds_toggle1to0(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG16_ADDR,
+			     CMU_REG16_PVT_UP_MAN_ENA_MASK, 0);
+
+	loopcount = 10;
+	do {
+		xgene_sds_rd(csr_serdes,
+			     KC_SERDES_CMU_REGS_CMU_REG7_ADDR, &val);
+		if (CMU_REG7_PLL_CALIB_DONE_RD(val))
+			break;
+		xgene_ahci_delayus(2000);
+	} while (--loopcount > 0);
+
+	xgene_sds_rd(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG7_ADDR, &val);
+	if (CMU_REG7_PLL_CALIB_DONE_RD(val) == 1)
+		PHYDEBUG("SATA%d SERDES PLL calibration done", ctx->cid);
+	if (CMU_REG7_VCO_CAL_FAIL_RD(val) == 0x0) {
+		PHYDEBUG("SERDES CALIB successful");
+	} else {
+		/* Assert SDS reset and recall calib function */
+		PHYERROR("SERDES CALIB FAILED due to VCO FAIL");
+		return -1;
+	}
+	if (xgene_ahci_is_A1())
+		xgene_ahci_out32_flush(csr_serdes + SATA_ENET_SDS_RST_CTL_ADDR,
+				       0x000000DF);
+
+	PHYDEBUG("SATA%d Checking TX ready", ctx->cid);
+	xgene_sds_rd(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG15_ADDR, &val);
+	PHYDEBUG("SERDES TX is %sready", val & 0x0300 ? "" : "NOT ");
+	return 0;
+}
+
+static void xgene_serdes_pdwn_force_vco(struct xgene_ahci_context *ctx)
+{
+	void *csr_serdes = ctx->csr_base + SATA_SERDES_OFFSET;
+	u32 val;
+
+	PHYDEBUG("serdes power down VCO");
+	xgene_sds_rd(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG16_ADDR, &val);
+	val = CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(val, 0x5);
+	xgene_sds_wr(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG16_ADDR, val);
+
+	xgene_sds_toggle1to0(csr_serdes,
+			     KC_SERDES_CMU_REGS_CMU_REG0_ADDR,
+			     CMU_REG0_PDOWN_MASK, 1000);
+	xgene_sds_toggle1to0(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG32_ADDR,
+			     CMU_REG32_FORCE_VCOCAL_START_MASK, 0);
+}
+
+static void xgene_serdes_tx_ssc_enable(struct xgene_ahci_context *ctx)
+{
+	void *csr_serdes = ctx->csr_base + SATA_SERDES_OFFSET;
+	u32 val;
+
+	xgene_sds_rd(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG35_ADDR, &val);
+	val = CMU_REG35_PLL_SSC_MOD_SET(val, 0x5f);
+	xgene_sds_wr(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG35_ADDR, val);
+
+	xgene_sds_rd(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG36_ADDR, &val);
+	val = CMU_REG36_PLL_SSC_VSTEP_SET(val, 33);	/* Gen3 == 33 */
+	val = CMU_REG36_PLL_SSC_EN_SET(val, 1);
+	val = CMU_REG36_PLL_SSC_DSMSEL_SET(val, 1);
+	xgene_sds_wr(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG36_ADDR, val);
+
+	xgene_sds_clrbits(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG5_ADDR,
+			  CMU_REG5_PLL_RESETB_MASK);
+	xgene_ahci_delayus(1000);	/* Allow Serdes to get reflected */
+	xgene_sds_setbits(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG5_ADDR,
+			  CMU_REG5_PLL_RESETB_MASK);
+	xgene_sds_toggle1to0(csr_serdes, KC_SERDES_CMU_REGS_CMU_REG32_ADDR,
+			     CMU_REG32_FORCE_VCOCAL_START_MASK, 0);
+}
+
+int xgene_ahci_serdes_init(struct xgene_ahci_context *ctx,
+			   int gen_sel, int clk_type, int rxwclk_inv)
+{
+	u32 val;
+	u32 ssc_enable = 0;
+	int calib_loop_count;
+	int rc = 0;
+	void *csr_base = ctx->csr_base;
+	void *csr_serdes_base = csr_base + SATA_SERDES_OFFSET;
+	void *clkcsr_base = ctx->csr_base + SATA_CLK_OFFSET;
+
+	PHYDEBUG("SATA%d PHY init speed %d clk type %d inv clk %d",
+		 ctx->cid, gen_sel, clk_type, rxwclk_inv);
+	PHYDEBUG("SATA%d ctrl_eq %d %d pq %d %d loopback %d %d ena_ctle %d %d spd_sel_cdr %d %d use_gen_avg %d",
+		 ctx->cid, ctx->ctrl_eq_A1, ctx->ctrl_eq, ctx->pq_A1, ctx->pq,
+		 ctx->loopback_buf_en_A1, ctx->loopback_buf_en,
+		 ctx->loopback_ena_ctle_A1, ctx->loopback_ena_ctle,
+		 ctx->spd_sel_cdr_A1, ctx->spd_sel_cdr, ctx->use_gen_avg);
+
+	if (ctx->cid == 2 && (clk_type == SATA_CLK_INT_DIFF ||
+			      clk_type == SATA_CLK_INT_SING)) {
+		xgene_serdes_sata45_macro_cfg(ctx);
+	}
+
+	/* Select SATA mux for SATA port 0 - 3 which shared with SGMII ETH */
+	if (ctx->cid < 2) {
+		if (xgene_serdes_host_sata_select(ctx) != 0) {
+			PHYERROR("SATA%d can not select SATA MUX", ctx->cid);
+			return -1;
+		}
+	}
+
+	/* Clock reset must before after select the MUX */
+	PHYDEBUG("SATA%d enable clock", ctx->cid);
+	xgene_serdes_clk_rst_pre(ctx);
+
+	if (ctx->cid != 2 && (clk_type == SATA_CLK_INT_DIFF ||
+			      clk_type == SATA_CLK_INT_SING))
+		xgene_serdes_sata_macro_cfg(ctx);
+
+	xgene_ahci_out32(csr_serdes_base + SATA_ENET_SDS_RST_CTL_ADDR, 0x00);
+	xgene_ahci_delayus(1000);	/* Allow IP to get reflected */
+	PHYDEBUG("SATA%d reset Serdes", ctx->cid);
+	/* 1. Serdes main reset and Controller also under reset */
+	xgene_ahci_out32(csr_serdes_base + SATA_ENET_SDS_RST_CTL_ADDR,
+			 0x00000020);
+
+	/* Release all resets except  main reset */
+	xgene_ahci_out32(csr_serdes_base + SATA_ENET_SDS_RST_CTL_ADDR,
+			 0x000000DE);
+
+	xgene_ahci_in32(csr_serdes_base + SATA_ENET_SDS_CTL1_ADDR, &val);
+	val = CFG_I_SPD_SEL_CDR_OVR1_SET(val, SPD_SEL);
+	xgene_ahci_out32(csr_serdes_base + SATA_ENET_SDS_CTL1_ADDR, val);
+
+	PHYDEBUG("SATA%d Setting the customer pin mode", ctx->cid);
+	/*
+	 * Clear customer pins mode[13:0] = 0
+	 * Set customer pins mode[14] = 1
+	 */
+	xgene_ahci_in32(csr_serdes_base + SATA_ENET_SDS_CTL0_ADDR, &val);
+	val = REGSPEC_CFG_I_CUSTOMER_PIN_MODE0_SET(val, 0x4421);
+	xgene_ahci_out32(csr_serdes_base + SATA_ENET_SDS_CTL0_ADDR, val);
+
+	/* CMU_REG12 tx ready delay 0x2 */
+	xgene_sds_rd(csr_serdes_base, KC_SERDES_CMU_REGS_CMU_REG12_ADDR, &val);
+	if (xgene_ahci_is_A1())
+		val = CMU_REG12_STATE_DELAY9_SET(val, 0x2);
+	else
+		val = CMU_REG12_STATE_DELAY9_SET(val, 0x1);
+	xgene_sds_wr(csr_serdes_base, KC_SERDES_CMU_REGS_CMU_REG12_ADDR, val);
+	xgene_sds_wr(csr_serdes_base,
+		     KC_SERDES_CMU_REGS_CMU_REG13_ADDR, 0xF222);
+	xgene_sds_wr(csr_serdes_base,
+		     KC_SERDES_CMU_REGS_CMU_REG14_ADDR, 0x2225);
+	if (clk_type == SATA_CLK_EXT_DIFF) {
+		xgene_sds_rd(csr_serdes_base,
+			     KC_SERDES_CMU_REGS_CMU_REG0_ADDR, &val);
+		val = CMU_REG0_PLL_REF_SEL_SET(val, 0x0);
+		xgene_sds_wr(csr_serdes_base,
+			     KC_SERDES_CMU_REGS_CMU_REG0_ADDR, val);
+		xgene_sds_rd(csr_serdes_base,
+			     KC_SERDES_CMU_REGS_CMU_REG1_ADDR, &val);
+		val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x0);
+		xgene_sds_wr(csr_serdes_base,
+			     KC_SERDES_CMU_REGS_CMU_REG1_ADDR, val);
+		PHYDEBUG("SATA%d Setting REFCLK EXTERNAL DIFF CML0", ctx->cid);
+	} else if (clk_type == SATA_CLK_INT_DIFF) {
+		xgene_sds_rd(csr_serdes_base,
+			     KC_SERDES_CMU_REGS_CMU_REG0_ADDR, &val);
+		val = CMU_REG0_PLL_REF_SEL_SET(val, 0x1);
+		xgene_sds_wr(csr_serdes_base,
+			     KC_SERDES_CMU_REGS_CMU_REG0_ADDR, val);
+		xgene_sds_rd(csr_serdes_base,
+			     KC_SERDES_CMU_REGS_CMU_REG1_ADDR, &val);
+		val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x1);
+		xgene_sds_wr(csr_serdes_base,
+			     KC_SERDES_CMU_REGS_CMU_REG1_ADDR, val);
+
+		PHYDEBUG("SATA%d Setting REFCLK INTERNAL DIFF CML1", ctx->cid);
+	} else if (clk_type == SATA_CLK_INT_SING) {
+		xgene_sds_rd(csr_serdes_base,
+			     KC_SERDES_CMU_REGS_CMU_REG1_ADDR, &val);
+		val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x1);
+		xgene_sds_wr(csr_serdes_base,
+			     KC_SERDES_CMU_REGS_CMU_REG1_ADDR, val);
+		PHYDEBUG("SATA%d Setting REFCLK INTERNAL CMOS", ctx->cid);
+	}
+	/* SATA4/5 no support for CML1 */
+	if (ctx->cid == 2 && clk_type == SATA_CLK_INT_DIFF)
+		xgene_sds_setbits(csr_serdes_base,
+				  KC_SERDES_CMU_REGS_CMU_REG1_ADDR,
+				  CMU_REG1_REFCLK_CMOS_SEL_MASK);
+	/* Setup clock inversion */
+	if (xgene_ahci_is_A1()) {
+		xgene_sds_rd(csr_serdes_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG13_ADDR, &val);
+		val &= ~(rxwclk_inv << 13);
+		val |= (rxwclk_inv << 13);
+		xgene_sds_wr(csr_serdes_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG13_ADDR, val);
+		xgene_sds_rd(csr_serdes_base,
+			     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG13_ADDR, &val);
+		xgene_sds_rd(csr_serdes_base,
+			     KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG13_ADDR, &val);
+		val &= ~(rxwclk_inv << 13);
+		val |= (rxwclk_inv << 13);
+		xgene_sds_wr(csr_serdes_base,
+			     KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG13_ADDR, val);
+		xgene_sds_rd(csr_serdes_base,
+			     KC_SERDES_X2_RXTX_REGS_CH1_RXTX_REG13_ADDR, &val);
+	}
+	/* 2. Program serdes registers */
+	xgene_serdes_validation_CMU_cfg(ctx);
+	if (ssc_enable)
+		xgene_serdes_tx_ssc_enable(ctx);
+	xgene_serdes_validation_rxtx_cfg(ctx, gen_sel);
+
+	xgene_ahci_in32(csr_serdes_base + SATA_ENET_SDS_PCS_CTL0_ADDR, &val);
+	val = REGSPEC_CFG_I_RX_WORDMODE0_SET(val, 0x3);
+	val = REGSPEC_CFG_I_TX_WORDMODE0_SET(val, 0x3);
+	xgene_ahci_out32(csr_serdes_base + SATA_ENET_SDS_PCS_CTL0_ADDR, val);
+
+	calib_loop_count = 10;
+	do {
+		rc = xgene_serdes_cal_rdy_chk(ctx);
+		if (rc == 0)
+			break;
+		xgene_serdes_pdwn_force_vco(ctx);
+	} while (++calib_loop_count > 0);
+	if (calib_loop_count <= 0)
+		return -1;
+
+	xgene_ahci_out32_flush(clkcsr_base + SATACLKENREG_ADDR, 0xff);
+
+	xgene_ahci_delayms(3);	/* Allow Serdes to get reflected */
+	xgene_serdes_reset_sds_pmclk_core(ctx);
+
+	xgene_ahci_delayms(3);	/* Allow Serdes to get reflected */
+	xgene_serdes_reset_pclk(ctx);
+
+	PHYDEBUG("SATA%d initialized PHY", ctx->cid);
+	return 0;
+}
+
+void xgene_ahci_serdes_force_gen(struct xgene_ahci_context *ctx, int chan,
+				 int gen)
+{
+	void *csr_base = ctx->csr_base;
+	void *csr_serdes = csr_base + SATA_SERDES_OFFSET;
+	u32 val;
+
+	xgene_ahci_in32(csr_serdes + SATA_ENET_SDS_CTL1_ADDR, &val);
+	val = CFG_I_SPD_SEL_CDR_OVR1_SET(val, gen);
+	xgene_ahci_out32(csr_serdes + SATA_ENET_SDS_CTL1_ADDR, val);
+
+	xgene_sds_rd(csr_serdes,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG0_ADDR + chan * 0x200,
+		     &val);
+	val = CH0_RXTX_REG0_CTLE_EQ_HR_SET(val, 0x1c);
+	val = CH0_RXTX_REG0_CTLE_EQ_QR_SET(val, 0x1c);
+	val = CH0_RXTX_REG0_CTLE_EQ_FR_SET(val, 0x1c);
+	xgene_sds_wr(csr_serdes,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG0_ADDR + chan * 0x200,
+		     val);
+}
+
+void xgene_ahci_serdes_set_pq(struct xgene_ahci_context *ctx, int chan,
+			      int data)
+{
+	void *csr_base = ctx->csr_base;
+	void *csr_serdes_base = csr_base + SATA_SERDES_OFFSET;
+	u32 val;
+
+	xgene_sds_rd(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG125_ADDR + chan * 0x200,
+		     &val);
+	val = CH0_RXTX_REG125_SIGN_PQ_SET(val, data);
+	if (data)
+		val = CH0_RXTX_REG125_PQ_REG_SET(val, 3);
+	else
+		val = CH0_RXTX_REG125_PQ_REG_SET(val, ctx->pq);
+	xgene_sds_wr(csr_serdes_base,
+		     KC_SERDES_X2_RXTX_REGS_CH0_RXTX_REG125_ADDR + chan * 0x200,
+		     val);
+	xgene_ahci_delayus(1000);	/* Allow Serdes to get reflected */
+}
