153d2a715SThierry Reding /*
253d2a715SThierry Reding  * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
353d2a715SThierry Reding  *
453d2a715SThierry Reding  * This program is free software; you can redistribute it and/or modify it
553d2a715SThierry Reding  * under the terms and conditions of the GNU General Public License,
653d2a715SThierry Reding  * version 2, as published by the Free Software Foundation.
753d2a715SThierry Reding  *
853d2a715SThierry Reding  * This program is distributed in the hope it will be useful, but WITHOUT
953d2a715SThierry Reding  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1053d2a715SThierry Reding  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
1153d2a715SThierry Reding  * more details.
1253d2a715SThierry Reding  */
1353d2a715SThierry Reding 
1453d2a715SThierry Reding #include <linux/delay.h>
1553d2a715SThierry Reding #include <linux/io.h>
1653d2a715SThierry Reding #include <linux/mailbox_client.h>
1753d2a715SThierry Reding #include <linux/module.h>
1853d2a715SThierry Reding #include <linux/of.h>
1953d2a715SThierry Reding #include <linux/phy/phy.h>
2053d2a715SThierry Reding #include <linux/platform_device.h>
2153d2a715SThierry Reding #include <linux/regulator/consumer.h>
2253d2a715SThierry Reding #include <linux/reset.h>
2353d2a715SThierry Reding #include <linux/slab.h>
2453d2a715SThierry Reding 
2553d2a715SThierry Reding #include <soc/tegra/fuse.h>
2653d2a715SThierry Reding 
2753d2a715SThierry Reding #include "xusb.h"
2853d2a715SThierry Reding 
2953d2a715SThierry Reding #define FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? 15 : 0)
3053d2a715SThierry Reding #define FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK 0x3f
3153d2a715SThierry Reding #define FUSE_SKU_CALIB_HS_IREF_CAP_SHIFT 13
3253d2a715SThierry Reding #define FUSE_SKU_CALIB_HS_IREF_CAP_MASK 0x3
3353d2a715SThierry Reding #define FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_SHIFT 11
3453d2a715SThierry Reding #define FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_MASK 0x3
3553d2a715SThierry Reding #define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT 7
3653d2a715SThierry Reding #define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK 0xf
3753d2a715SThierry Reding 
3853d2a715SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP 0x008
3953d2a715SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(x) ((x) * 4)
4053d2a715SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP_PORT_CAP_MASK 0x3
4153d2a715SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP_DISABLED 0x0
4253d2a715SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP_HOST 0x1
4353d2a715SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP_DEVICE 0x2
4453d2a715SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP_OTG 0x3
4553d2a715SThierry Reding 
4653d2a715SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP 0x014
4753d2a715SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(x) (1 << (((x) * 4) + 3))
4853d2a715SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_SHIFT(x) ((x) * 4)
4953d2a715SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(x) (0x7 << ((x) * 4))
5053d2a715SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(x, v) (((v) & 0x7) << ((x) * 4))
5153d2a715SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORT_MAP_MASK 0x7
5253d2a715SThierry Reding 
5353d2a715SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM 0x01c
5453d2a715SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26)
5553d2a715SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25)
5653d2a715SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24)
5753d2a715SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(x) (1 << (18 + (x) * 4))
5853d2a715SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(x) \
5953d2a715SThierry Reding 							(1 << (17 + (x) * 4))
6053d2a715SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN(x) (1 << (16 + (x) * 4))
6153d2a715SThierry Reding 
6253d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040
6353d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19)
6453d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK (0xf << 12)
6553d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1)
6653d2a715SThierry Reding 
6753d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044
6853d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6)
6953d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5)
7053d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4)
7153d2a715SThierry Reding 
7253d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(x) (0x058 + (x) * 4)
7353d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT 24
7453d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK 0xff
7553d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_VAL 0x24
7653d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT 16
7753d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK 0x3f
7853d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT 8
7953d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK 0x3f
8053d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT 8
8153d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK 0xffff
8253d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_VAL 0xf070
8353d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT 4
8453d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK 0xf
8553d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_VAL 0xf
8653d2a715SThierry Reding 
8753d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(x) (0x068 + (x) * 4)
8853d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT 24
8953d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK 0x1f
9053d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT 16
9153d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK 0x7f
9253d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_VAL 0x002008ee
9353d2a715SThierry Reding 
9453d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL2(x) ((x) < 2 ? 0x078 + (x) * 4 : \
9553d2a715SThierry Reding 					       0x0f8 + (x) * 4)
9653d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT 28
9753d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_MASK 0x3
9853d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_VAL 0x1
9953d2a715SThierry Reding 
10053d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL5(x) ((x) < 2 ? 0x090 + (x) * 4 : \
10153d2a715SThierry Reding 					       0x11c + (x) * 4)
10253d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL5_RX_QEYE_EN (1 << 8)
10353d2a715SThierry Reding 
10453d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL6(x) ((x) < 2 ? 0x098 + (x) * 4 : \
10553d2a715SThierry Reding 					       0x128 + (x) * 4)
10653d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT 24
10753d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK 0x3f
10853d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_TAP_MASK 0x1f
10953d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_AMP_MASK 0x7f
11053d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT 16
11153d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK 0xff
11253d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_G_Z 0x21
11353d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_TAP 0x32
11453d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_AMP 0x33
11553d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_CTLE_Z 0x48
11653d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_LATCH_G_Z 0xa1
11753d2a715SThierry Reding 
11853d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x0a0 + (x) * 4)
11953d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI (1 << 21)
12053d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 (1 << 20)
12153d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD (1 << 19)
12253d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT 14
12353d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_MASK 0x3
12453d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_VAL(x) ((x) ? 0x0 : 0x3)
12553d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT 6
12653d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_MASK 0x3f
12753d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_VAL 0x0e
12853d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT 0
12953d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK 0x3f
13053d2a715SThierry Reding 
13153d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x) (0x0ac + (x) * 4)
13253d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT 9
13353d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_MASK 0x3
13453d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT 3
13553d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK 0x7
13653d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2)
13753d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP (1 << 1)
13853d2a715SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP (1 << 0)
13953d2a715SThierry Reding 
14053d2a715SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x0b8
14153d2a715SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 12)
14253d2a715SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT 2
14353d2a715SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK 0x7
14453d2a715SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL 0x5
14553d2a715SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT 0
14653d2a715SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK 0x3
14753d2a715SThierry Reding 
14853d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x0c0 + (x) * 4)
14953d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT 12
15053d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK 0x7
15153d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT 8
15253d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK 0x7
15353d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT 4
15453d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK 0x7
15553d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT 0
15653d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK 0x7
15753d2a715SThierry Reding 
15853d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PADX_CTL1(x) (0x0c8 + (x) * 4)
15953d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE (1 << 10)
16053d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL1_RPU_DATA (1 << 9)
16153d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL1_RPD_STROBE (1 << 8)
16253d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA (1 << 7)
16353d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI (1 << 5)
16453d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX (1 << 4)
16553d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX (1 << 3)
16653d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX (1 << 2)
16753d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN (1 << 0)
16853d2a715SThierry Reding 
16953d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PADX_CTL2(x) (0x0d0 + (x) * 4)
17053d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT 4
17153d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK 0x7
17253d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT 0
17353d2a715SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK 0x7
17453d2a715SThierry Reding 
17553d2a715SThierry Reding #define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL 0x0e0
17653d2a715SThierry Reding #define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_STRB_TRIM_MASK 0x1f
17753d2a715SThierry Reding 
17853d2a715SThierry Reding #define XUSB_PADCTL_USB3_PAD_MUX 0x134
17953d2a715SThierry Reding #define XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(x) (1 << (1 + (x)))
18053d2a715SThierry Reding #define XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(x) (1 << (6 + (x)))
18153d2a715SThierry Reding 
18253d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138
18353d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27)
18453d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24)
18553d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_SHIFT 20
18653d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_MASK 0x3
18753d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3)
18853d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST (1 << 1)
18953d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0)
19053d2a715SThierry Reding 
19153d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2 0x13c
19253d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_SHIFT 20
19353d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_MASK 0xf
19453d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_SHIFT 16
19553d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_MASK 0xf
19653d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TCLKOUT_EN (1 << 12)
19753d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TXCLKREF_SEL (1 << 4)
19853d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_SHIFT 0
19953d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_MASK 0x7
20053d2a715SThierry Reding 
20153d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL3 0x140
20253d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_PLL_S0_CTL3_RCAL_BYPASS (1 << 7)
20353d2a715SThierry Reding 
20453d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148
20553d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1)
20653d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0)
20753d2a715SThierry Reding 
20853d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 0x14c
20953d2a715SThierry Reding 
21053d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 0x158
21153d2a715SThierry Reding 
21253d2a715SThierry Reding #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 0x15c
21353d2a715SThierry Reding 
21453d2a715SThierry Reding struct tegra124_xusb_fuse_calibration {
21553d2a715SThierry Reding 	u32 hs_curr_level[3];
21653d2a715SThierry Reding 	u32 hs_iref_cap;
21753d2a715SThierry Reding 	u32 hs_term_range_adj;
21853d2a715SThierry Reding 	u32 hs_squelch_level;
21953d2a715SThierry Reding };
22053d2a715SThierry Reding 
22153d2a715SThierry Reding struct tegra124_xusb_padctl {
22253d2a715SThierry Reding 	struct tegra_xusb_padctl base;
22353d2a715SThierry Reding 
22453d2a715SThierry Reding 	struct tegra124_xusb_fuse_calibration fuse;
22553d2a715SThierry Reding };
22653d2a715SThierry Reding 
22753d2a715SThierry Reding static inline struct tegra124_xusb_padctl *
22853d2a715SThierry Reding to_tegra124_xusb_padctl(struct tegra_xusb_padctl *padctl)
22953d2a715SThierry Reding {
23053d2a715SThierry Reding 	return container_of(padctl, struct tegra124_xusb_padctl, base);
23153d2a715SThierry Reding }
23253d2a715SThierry Reding 
23353d2a715SThierry Reding static int tegra124_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
23453d2a715SThierry Reding {
23553d2a715SThierry Reding 	u32 value;
23653d2a715SThierry Reding 
23753d2a715SThierry Reding 	mutex_lock(&padctl->lock);
23853d2a715SThierry Reding 
23953d2a715SThierry Reding 	if (padctl->enable++ > 0)
24053d2a715SThierry Reding 		goto out;
24153d2a715SThierry Reding 
24253d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
24353d2a715SThierry Reding 	value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
24453d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
24553d2a715SThierry Reding 
24653d2a715SThierry Reding 	usleep_range(100, 200);
24753d2a715SThierry Reding 
24853d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
24953d2a715SThierry Reding 	value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
25053d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
25153d2a715SThierry Reding 
25253d2a715SThierry Reding 	usleep_range(100, 200);
25353d2a715SThierry Reding 
25453d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
25553d2a715SThierry Reding 	value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
25653d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
25753d2a715SThierry Reding 
25853d2a715SThierry Reding out:
25953d2a715SThierry Reding 	mutex_unlock(&padctl->lock);
26053d2a715SThierry Reding 	return 0;
26153d2a715SThierry Reding }
26253d2a715SThierry Reding 
26353d2a715SThierry Reding static int tegra124_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
26453d2a715SThierry Reding {
26553d2a715SThierry Reding 	u32 value;
26653d2a715SThierry Reding 
26753d2a715SThierry Reding 	mutex_lock(&padctl->lock);
26853d2a715SThierry Reding 
26953d2a715SThierry Reding 	if (WARN_ON(padctl->enable == 0))
27053d2a715SThierry Reding 		goto out;
27153d2a715SThierry Reding 
27253d2a715SThierry Reding 	if (--padctl->enable > 0)
27353d2a715SThierry Reding 		goto out;
27453d2a715SThierry Reding 
27553d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
27653d2a715SThierry Reding 	value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
27753d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
27853d2a715SThierry Reding 
27953d2a715SThierry Reding 	usleep_range(100, 200);
28053d2a715SThierry Reding 
28153d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
28253d2a715SThierry Reding 	value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
28353d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
28453d2a715SThierry Reding 
28553d2a715SThierry Reding 	usleep_range(100, 200);
28653d2a715SThierry Reding 
28753d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
28853d2a715SThierry Reding 	value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
28953d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
29053d2a715SThierry Reding 
29153d2a715SThierry Reding out:
29253d2a715SThierry Reding 	mutex_unlock(&padctl->lock);
29353d2a715SThierry Reding 	return 0;
29453d2a715SThierry Reding }
29553d2a715SThierry Reding 
29653d2a715SThierry Reding static int tegra124_usb3_save_context(struct tegra_xusb_padctl *padctl,
29753d2a715SThierry Reding 				      unsigned int index)
29853d2a715SThierry Reding {
29953d2a715SThierry Reding 	struct tegra_xusb_usb3_port *port;
30053d2a715SThierry Reding 	struct tegra_xusb_lane *lane;
30153d2a715SThierry Reding 	u32 value, offset;
30253d2a715SThierry Reding 
30353d2a715SThierry Reding 	port = tegra_xusb_find_usb3_port(padctl, index);
30453d2a715SThierry Reding 	if (!port)
30553d2a715SThierry Reding 		return -ENODEV;
30653d2a715SThierry Reding 
30753d2a715SThierry Reding 	port->context_saved = true;
30853d2a715SThierry Reding 	lane = port->base.lane;
30953d2a715SThierry Reding 
31053d2a715SThierry Reding 	if (lane->pad == padctl->pcie)
31153d2a715SThierry Reding 		offset = XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL6(lane->index);
31253d2a715SThierry Reding 	else
31353d2a715SThierry Reding 		offset = XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6;
31453d2a715SThierry Reding 
31553d2a715SThierry Reding 	value = padctl_readl(padctl, offset);
31653d2a715SThierry Reding 	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
31753d2a715SThierry Reding 		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
31853d2a715SThierry Reding 	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_TAP <<
31953d2a715SThierry Reding 		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
32053d2a715SThierry Reding 	padctl_writel(padctl, value, offset);
32153d2a715SThierry Reding 
32253d2a715SThierry Reding 	value = padctl_readl(padctl, offset) >>
32353d2a715SThierry Reding 		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
32453d2a715SThierry Reding 	port->tap1 = value & XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_TAP_MASK;
32553d2a715SThierry Reding 
32653d2a715SThierry Reding 	value = padctl_readl(padctl, offset);
32753d2a715SThierry Reding 	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
32853d2a715SThierry Reding 		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
32953d2a715SThierry Reding 	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_AMP <<
33053d2a715SThierry Reding 		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
33153d2a715SThierry Reding 	padctl_writel(padctl, value, offset);
33253d2a715SThierry Reding 
33353d2a715SThierry Reding 	value = padctl_readl(padctl, offset) >>
33453d2a715SThierry Reding 		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
33553d2a715SThierry Reding 	port->amp = value & XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_AMP_MASK;
33653d2a715SThierry Reding 
33753d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(index));
33853d2a715SThierry Reding 	value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK <<
33953d2a715SThierry Reding 		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
34053d2a715SThierry Reding 		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK <<
34153d2a715SThierry Reding 		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT));
34253d2a715SThierry Reding 	value |= (port->tap1 <<
34353d2a715SThierry Reding 		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
34453d2a715SThierry Reding 		 (port->amp <<
34553d2a715SThierry Reding 		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT);
34653d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(index));
34753d2a715SThierry Reding 
34853d2a715SThierry Reding 	value = padctl_readl(padctl, offset);
34953d2a715SThierry Reding 	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
35053d2a715SThierry Reding 		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
35153d2a715SThierry Reding 	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_LATCH_G_Z <<
35253d2a715SThierry Reding 		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
35353d2a715SThierry Reding 	padctl_writel(padctl, value, offset);
35453d2a715SThierry Reding 
35553d2a715SThierry Reding 	value = padctl_readl(padctl, offset);
35653d2a715SThierry Reding 	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
35753d2a715SThierry Reding 		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
35853d2a715SThierry Reding 	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_G_Z <<
35953d2a715SThierry Reding 		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
36053d2a715SThierry Reding 	padctl_writel(padctl, value, offset);
36153d2a715SThierry Reding 
36253d2a715SThierry Reding 	value = padctl_readl(padctl, offset) >>
36353d2a715SThierry Reding 		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
36453d2a715SThierry Reding 	port->ctle_g = value &
36553d2a715SThierry Reding 		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK;
36653d2a715SThierry Reding 
36753d2a715SThierry Reding 	value = padctl_readl(padctl, offset);
36853d2a715SThierry Reding 	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
36953d2a715SThierry Reding 		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
37053d2a715SThierry Reding 	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_CTLE_Z <<
37153d2a715SThierry Reding 		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
37253d2a715SThierry Reding 	padctl_writel(padctl, value, offset);
37353d2a715SThierry Reding 
37453d2a715SThierry Reding 	value = padctl_readl(padctl, offset) >>
37553d2a715SThierry Reding 		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
37653d2a715SThierry Reding 	port->ctle_z = value &
37753d2a715SThierry Reding 		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK;
37853d2a715SThierry Reding 
37953d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(index));
38053d2a715SThierry Reding 	value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK <<
38153d2a715SThierry Reding 		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
38253d2a715SThierry Reding 		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK <<
38353d2a715SThierry Reding 		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT));
38453d2a715SThierry Reding 	value |= (port->ctle_g <<
38553d2a715SThierry Reding 		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
38653d2a715SThierry Reding 		 (port->ctle_z <<
38753d2a715SThierry Reding 		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT);
38853d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(index));
38953d2a715SThierry Reding 
39053d2a715SThierry Reding 	return 0;
39153d2a715SThierry Reding }
39253d2a715SThierry Reding 
39353d2a715SThierry Reding static int tegra124_hsic_set_idle(struct tegra_xusb_padctl *padctl,
39453d2a715SThierry Reding 				  unsigned int index, bool idle)
39553d2a715SThierry Reding {
39653d2a715SThierry Reding 	u32 value;
39753d2a715SThierry Reding 
39853d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index));
39953d2a715SThierry Reding 
40053d2a715SThierry Reding 	if (idle)
40153d2a715SThierry Reding 		value |= XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA |
40253d2a715SThierry Reding 			 XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE;
40353d2a715SThierry Reding 	else
40453d2a715SThierry Reding 		value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA |
40553d2a715SThierry Reding 			   XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE);
40653d2a715SThierry Reding 
40753d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index));
40853d2a715SThierry Reding 
40953d2a715SThierry Reding 	return 0;
41053d2a715SThierry Reding }
41153d2a715SThierry Reding 
41253d2a715SThierry Reding #define TEGRA124_LANE(_name, _offset, _shift, _mask, _type)		\
41353d2a715SThierry Reding 	{								\
41453d2a715SThierry Reding 		.name = _name,						\
41553d2a715SThierry Reding 		.offset = _offset,					\
41653d2a715SThierry Reding 		.shift = _shift,					\
41753d2a715SThierry Reding 		.mask = _mask,						\
41853d2a715SThierry Reding 		.num_funcs = ARRAY_SIZE(tegra124_##_type##_functions),	\
41953d2a715SThierry Reding 		.funcs = tegra124_##_type##_functions,			\
42053d2a715SThierry Reding 	}
42153d2a715SThierry Reding 
42253d2a715SThierry Reding static const char * const tegra124_usb2_functions[] = {
42353d2a715SThierry Reding 	"snps",
42453d2a715SThierry Reding 	"xusb",
42553d2a715SThierry Reding 	"uart",
42653d2a715SThierry Reding };
42753d2a715SThierry Reding 
42853d2a715SThierry Reding static const struct tegra_xusb_lane_soc tegra124_usb2_lanes[] = {
42953d2a715SThierry Reding 	TEGRA124_LANE("usb2-0", 0x004,  0, 0x3, usb2),
43053d2a715SThierry Reding 	TEGRA124_LANE("usb2-1", 0x004,  2, 0x3, usb2),
43153d2a715SThierry Reding 	TEGRA124_LANE("usb2-2", 0x004,  4, 0x3, usb2),
43253d2a715SThierry Reding };
43353d2a715SThierry Reding 
43453d2a715SThierry Reding static struct tegra_xusb_lane *
43553d2a715SThierry Reding tegra124_usb2_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
43653d2a715SThierry Reding 			 unsigned int index)
43753d2a715SThierry Reding {
43853d2a715SThierry Reding 	struct tegra_xusb_usb2_lane *usb2;
43953d2a715SThierry Reding 	int err;
44053d2a715SThierry Reding 
44153d2a715SThierry Reding 	usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
44253d2a715SThierry Reding 	if (!usb2)
44353d2a715SThierry Reding 		return ERR_PTR(-ENOMEM);
44453d2a715SThierry Reding 
44553d2a715SThierry Reding 	INIT_LIST_HEAD(&usb2->base.list);
44653d2a715SThierry Reding 	usb2->base.soc = &pad->soc->lanes[index];
44753d2a715SThierry Reding 	usb2->base.index = index;
44853d2a715SThierry Reding 	usb2->base.pad = pad;
44953d2a715SThierry Reding 	usb2->base.np = np;
45053d2a715SThierry Reding 
45153d2a715SThierry Reding 	err = tegra_xusb_lane_parse_dt(&usb2->base, np);
45253d2a715SThierry Reding 	if (err < 0) {
45353d2a715SThierry Reding 		kfree(usb2);
45453d2a715SThierry Reding 		return ERR_PTR(err);
45553d2a715SThierry Reding 	}
45653d2a715SThierry Reding 
45753d2a715SThierry Reding 	return &usb2->base;
45853d2a715SThierry Reding }
45953d2a715SThierry Reding 
46053d2a715SThierry Reding static void tegra124_usb2_lane_remove(struct tegra_xusb_lane *lane)
46153d2a715SThierry Reding {
46253d2a715SThierry Reding 	struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane);
46353d2a715SThierry Reding 
46453d2a715SThierry Reding 	kfree(usb2);
46553d2a715SThierry Reding }
46653d2a715SThierry Reding 
46753d2a715SThierry Reding static const struct tegra_xusb_lane_ops tegra124_usb2_lane_ops = {
46853d2a715SThierry Reding 	.probe = tegra124_usb2_lane_probe,
46953d2a715SThierry Reding 	.remove = tegra124_usb2_lane_remove,
47053d2a715SThierry Reding };
47153d2a715SThierry Reding 
47253d2a715SThierry Reding static int tegra124_usb2_phy_init(struct phy *phy)
47353d2a715SThierry Reding {
47453d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
47553d2a715SThierry Reding 
47653d2a715SThierry Reding 	return tegra124_xusb_padctl_enable(lane->pad->padctl);
47753d2a715SThierry Reding }
47853d2a715SThierry Reding 
47953d2a715SThierry Reding static int tegra124_usb2_phy_exit(struct phy *phy)
48053d2a715SThierry Reding {
48153d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
48253d2a715SThierry Reding 
48353d2a715SThierry Reding 	return tegra124_xusb_padctl_disable(lane->pad->padctl);
48453d2a715SThierry Reding }
48553d2a715SThierry Reding 
48653d2a715SThierry Reding static int tegra124_usb2_phy_power_on(struct phy *phy)
48753d2a715SThierry Reding {
48853d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
48953d2a715SThierry Reding 	struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane);
49053d2a715SThierry Reding 	struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad);
49153d2a715SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
49253d2a715SThierry Reding 	struct tegra124_xusb_padctl *priv;
49353d2a715SThierry Reding 	struct tegra_xusb_usb2_port *port;
49453d2a715SThierry Reding 	unsigned int index = lane->index;
49553d2a715SThierry Reding 	u32 value;
49653d2a715SThierry Reding 	int err;
49753d2a715SThierry Reding 
49853d2a715SThierry Reding 	port = tegra_xusb_find_usb2_port(padctl, index);
49953d2a715SThierry Reding 	if (!port) {
50053d2a715SThierry Reding 		dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
50153d2a715SThierry Reding 		return -ENODEV;
50253d2a715SThierry Reding 	}
50353d2a715SThierry Reding 
50453d2a715SThierry Reding 	priv = to_tegra124_xusb_padctl(padctl);
50553d2a715SThierry Reding 
50653d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
50753d2a715SThierry Reding 	value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK <<
50853d2a715SThierry Reding 		    XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) |
50953d2a715SThierry Reding 		   (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK <<
51053d2a715SThierry Reding 		    XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT));
51153d2a715SThierry Reding 	value |= (priv->fuse.hs_squelch_level <<
51253d2a715SThierry Reding 		  XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) |
51353d2a715SThierry Reding 		 (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL <<
51453d2a715SThierry Reding 		  XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT);
51553d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
51653d2a715SThierry Reding 
51753d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
51853d2a715SThierry Reding 	value &= ~(XUSB_PADCTL_USB2_PORT_CAP_PORT_CAP_MASK <<
51953d2a715SThierry Reding 		   XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(index));
52053d2a715SThierry Reding 	value |= XUSB_PADCTL_USB2_PORT_CAP_HOST <<
52153d2a715SThierry Reding 		XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(index);
52253d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP);
52353d2a715SThierry Reding 
52453d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
52553d2a715SThierry Reding 	value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK <<
52653d2a715SThierry Reding 		    XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT) |
52753d2a715SThierry Reding 		   (XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_MASK <<
52853d2a715SThierry Reding 		    XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT) |
52953d2a715SThierry Reding 		   (XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_MASK <<
53053d2a715SThierry Reding 		    XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT) |
53153d2a715SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD |
53253d2a715SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 |
53353d2a715SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI);
53453d2a715SThierry Reding 	value |= (priv->fuse.hs_curr_level[index] +
53553d2a715SThierry Reding 		  usb2->hs_curr_level_offset) <<
53653d2a715SThierry Reding 		XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT;
53753d2a715SThierry Reding 	value |= XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_VAL <<
53853d2a715SThierry Reding 		XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT;
53953d2a715SThierry Reding 	value |= XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_VAL(index) <<
54053d2a715SThierry Reding 		XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT;
54153d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
54253d2a715SThierry Reding 
54353d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
54453d2a715SThierry Reding 	value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK <<
54553d2a715SThierry Reding 		    XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) |
54653d2a715SThierry Reding 		   (XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_MASK <<
54753d2a715SThierry Reding 		    XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT) |
54853d2a715SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR |
54953d2a715SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP |
55053d2a715SThierry Reding 		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP);
55153d2a715SThierry Reding 	value |= (priv->fuse.hs_term_range_adj <<
55253d2a715SThierry Reding 		  XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) |
55353d2a715SThierry Reding 		 (priv->fuse.hs_iref_cap <<
55453d2a715SThierry Reding 		  XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT);
55553d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
55653d2a715SThierry Reding 
55753d2a715SThierry Reding 	err = regulator_enable(port->supply);
55853d2a715SThierry Reding 	if (err)
55953d2a715SThierry Reding 		return err;
56053d2a715SThierry Reding 
56153d2a715SThierry Reding 	mutex_lock(&pad->lock);
56253d2a715SThierry Reding 
56353d2a715SThierry Reding 	if (pad->enable++ > 0)
56453d2a715SThierry Reding 		goto out;
56553d2a715SThierry Reding 
56653d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
56753d2a715SThierry Reding 	value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
56853d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
56953d2a715SThierry Reding 
57053d2a715SThierry Reding out:
57153d2a715SThierry Reding 	mutex_unlock(&pad->lock);
57253d2a715SThierry Reding 	return 0;
57353d2a715SThierry Reding }
57453d2a715SThierry Reding 
57553d2a715SThierry Reding static int tegra124_usb2_phy_power_off(struct phy *phy)
57653d2a715SThierry Reding {
57753d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
57853d2a715SThierry Reding 	struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad);
57953d2a715SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
58053d2a715SThierry Reding 	struct tegra_xusb_usb2_port *port;
58153d2a715SThierry Reding 	u32 value;
58253d2a715SThierry Reding 
58353d2a715SThierry Reding 	port = tegra_xusb_find_usb2_port(padctl, lane->index);
58453d2a715SThierry Reding 	if (!port) {
58553d2a715SThierry Reding 		dev_err(&phy->dev, "no port found for USB2 lane %u\n",
58653d2a715SThierry Reding 			lane->index);
58753d2a715SThierry Reding 		return -ENODEV;
58853d2a715SThierry Reding 	}
58953d2a715SThierry Reding 
59053d2a715SThierry Reding 	mutex_lock(&pad->lock);
59153d2a715SThierry Reding 
59253d2a715SThierry Reding 	if (WARN_ON(pad->enable == 0))
59353d2a715SThierry Reding 		goto out;
59453d2a715SThierry Reding 
59553d2a715SThierry Reding 	if (--pad->enable > 0)
59653d2a715SThierry Reding 		goto out;
59753d2a715SThierry Reding 
59853d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
59953d2a715SThierry Reding 	value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
60053d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
60153d2a715SThierry Reding 
60253d2a715SThierry Reding out:
60353d2a715SThierry Reding 	regulator_disable(port->supply);
60453d2a715SThierry Reding 	mutex_unlock(&pad->lock);
60553d2a715SThierry Reding 	return 0;
60653d2a715SThierry Reding }
60753d2a715SThierry Reding 
60853d2a715SThierry Reding static const struct phy_ops tegra124_usb2_phy_ops = {
60953d2a715SThierry Reding 	.init = tegra124_usb2_phy_init,
61053d2a715SThierry Reding 	.exit = tegra124_usb2_phy_exit,
61153d2a715SThierry Reding 	.power_on = tegra124_usb2_phy_power_on,
61253d2a715SThierry Reding 	.power_off = tegra124_usb2_phy_power_off,
61353d2a715SThierry Reding 	.owner = THIS_MODULE,
61453d2a715SThierry Reding };
61553d2a715SThierry Reding 
61653d2a715SThierry Reding static struct tegra_xusb_pad *
61753d2a715SThierry Reding tegra124_usb2_pad_probe(struct tegra_xusb_padctl *padctl,
61853d2a715SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
61953d2a715SThierry Reding 			struct device_node *np)
62053d2a715SThierry Reding {
62153d2a715SThierry Reding 	struct tegra_xusb_usb2_pad *usb2;
62253d2a715SThierry Reding 	struct tegra_xusb_pad *pad;
62353d2a715SThierry Reding 	int err;
62453d2a715SThierry Reding 
62553d2a715SThierry Reding 	usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
62653d2a715SThierry Reding 	if (!usb2)
62753d2a715SThierry Reding 		return ERR_PTR(-ENOMEM);
62853d2a715SThierry Reding 
62953d2a715SThierry Reding 	mutex_init(&usb2->lock);
63053d2a715SThierry Reding 
63153d2a715SThierry Reding 	pad = &usb2->base;
63253d2a715SThierry Reding 	pad->ops = &tegra124_usb2_lane_ops;
63353d2a715SThierry Reding 	pad->soc = soc;
63453d2a715SThierry Reding 
63553d2a715SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
63653d2a715SThierry Reding 	if (err < 0) {
63753d2a715SThierry Reding 		kfree(usb2);
63853d2a715SThierry Reding 		goto out;
63953d2a715SThierry Reding 	}
64053d2a715SThierry Reding 
64153d2a715SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra124_usb2_phy_ops);
64253d2a715SThierry Reding 	if (err < 0)
64353d2a715SThierry Reding 		goto unregister;
64453d2a715SThierry Reding 
64553d2a715SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
64653d2a715SThierry Reding 
64753d2a715SThierry Reding 	return pad;
64853d2a715SThierry Reding 
64953d2a715SThierry Reding unregister:
65053d2a715SThierry Reding 	device_unregister(&pad->dev);
65153d2a715SThierry Reding out:
65253d2a715SThierry Reding 	return ERR_PTR(err);
65353d2a715SThierry Reding }
65453d2a715SThierry Reding 
65553d2a715SThierry Reding static void tegra124_usb2_pad_remove(struct tegra_xusb_pad *pad)
65653d2a715SThierry Reding {
65753d2a715SThierry Reding 	struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad);
65853d2a715SThierry Reding 
65953d2a715SThierry Reding 	kfree(usb2);
66053d2a715SThierry Reding }
66153d2a715SThierry Reding 
66253d2a715SThierry Reding static const struct tegra_xusb_pad_ops tegra124_usb2_ops = {
66353d2a715SThierry Reding 	.probe = tegra124_usb2_pad_probe,
66453d2a715SThierry Reding 	.remove = tegra124_usb2_pad_remove,
66553d2a715SThierry Reding };
66653d2a715SThierry Reding 
66753d2a715SThierry Reding static const struct tegra_xusb_pad_soc tegra124_usb2_pad = {
66853d2a715SThierry Reding 	.name = "usb2",
66953d2a715SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra124_usb2_lanes),
67053d2a715SThierry Reding 	.lanes = tegra124_usb2_lanes,
67153d2a715SThierry Reding 	.ops = &tegra124_usb2_ops,
67253d2a715SThierry Reding };
67353d2a715SThierry Reding 
67453d2a715SThierry Reding static const char * const tegra124_ulpi_functions[] = {
67553d2a715SThierry Reding 	"snps",
67653d2a715SThierry Reding 	"xusb",
67753d2a715SThierry Reding };
67853d2a715SThierry Reding 
67953d2a715SThierry Reding static const struct tegra_xusb_lane_soc tegra124_ulpi_lanes[] = {
68053d2a715SThierry Reding 	TEGRA124_LANE("ulpi-0", 0x004, 12, 0x1, ulpi),
68153d2a715SThierry Reding };
68253d2a715SThierry Reding 
68353d2a715SThierry Reding static struct tegra_xusb_lane *
68453d2a715SThierry Reding tegra124_ulpi_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
68553d2a715SThierry Reding 			 unsigned int index)
68653d2a715SThierry Reding {
68753d2a715SThierry Reding 	struct tegra_xusb_ulpi_lane *ulpi;
68853d2a715SThierry Reding 	int err;
68953d2a715SThierry Reding 
69053d2a715SThierry Reding 	ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL);
69153d2a715SThierry Reding 	if (!ulpi)
69253d2a715SThierry Reding 		return ERR_PTR(-ENOMEM);
69353d2a715SThierry Reding 
69453d2a715SThierry Reding 	INIT_LIST_HEAD(&ulpi->base.list);
69553d2a715SThierry Reding 	ulpi->base.soc = &pad->soc->lanes[index];
69653d2a715SThierry Reding 	ulpi->base.index = index;
69753d2a715SThierry Reding 	ulpi->base.pad = pad;
69853d2a715SThierry Reding 	ulpi->base.np = np;
69953d2a715SThierry Reding 
70053d2a715SThierry Reding 	err = tegra_xusb_lane_parse_dt(&ulpi->base, np);
70153d2a715SThierry Reding 	if (err < 0) {
70253d2a715SThierry Reding 		kfree(ulpi);
70353d2a715SThierry Reding 		return ERR_PTR(err);
70453d2a715SThierry Reding 	}
70553d2a715SThierry Reding 
70653d2a715SThierry Reding 	return &ulpi->base;
70753d2a715SThierry Reding }
70853d2a715SThierry Reding 
70953d2a715SThierry Reding static void tegra124_ulpi_lane_remove(struct tegra_xusb_lane *lane)
71053d2a715SThierry Reding {
71153d2a715SThierry Reding 	struct tegra_xusb_ulpi_lane *ulpi = to_ulpi_lane(lane);
71253d2a715SThierry Reding 
71353d2a715SThierry Reding 	kfree(ulpi);
71453d2a715SThierry Reding }
71553d2a715SThierry Reding 
71653d2a715SThierry Reding static const struct tegra_xusb_lane_ops tegra124_ulpi_lane_ops = {
71753d2a715SThierry Reding 	.probe = tegra124_ulpi_lane_probe,
71853d2a715SThierry Reding 	.remove = tegra124_ulpi_lane_remove,
71953d2a715SThierry Reding };
72053d2a715SThierry Reding 
72153d2a715SThierry Reding static int tegra124_ulpi_phy_init(struct phy *phy)
72253d2a715SThierry Reding {
72353d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
72453d2a715SThierry Reding 
72553d2a715SThierry Reding 	return tegra124_xusb_padctl_enable(lane->pad->padctl);
72653d2a715SThierry Reding }
72753d2a715SThierry Reding 
72853d2a715SThierry Reding static int tegra124_ulpi_phy_exit(struct phy *phy)
72953d2a715SThierry Reding {
73053d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
73153d2a715SThierry Reding 
73253d2a715SThierry Reding 	return tegra124_xusb_padctl_disable(lane->pad->padctl);
73353d2a715SThierry Reding }
73453d2a715SThierry Reding 
73553d2a715SThierry Reding static int tegra124_ulpi_phy_power_on(struct phy *phy)
73653d2a715SThierry Reding {
73753d2a715SThierry Reding 	return 0;
73853d2a715SThierry Reding }
73953d2a715SThierry Reding 
74053d2a715SThierry Reding static int tegra124_ulpi_phy_power_off(struct phy *phy)
74153d2a715SThierry Reding {
74253d2a715SThierry Reding 	return 0;
74353d2a715SThierry Reding }
74453d2a715SThierry Reding 
74553d2a715SThierry Reding static const struct phy_ops tegra124_ulpi_phy_ops = {
74653d2a715SThierry Reding 	.init = tegra124_ulpi_phy_init,
74753d2a715SThierry Reding 	.exit = tegra124_ulpi_phy_exit,
74853d2a715SThierry Reding 	.power_on = tegra124_ulpi_phy_power_on,
74953d2a715SThierry Reding 	.power_off = tegra124_ulpi_phy_power_off,
75053d2a715SThierry Reding 	.owner = THIS_MODULE,
75153d2a715SThierry Reding };
75253d2a715SThierry Reding 
75353d2a715SThierry Reding static struct tegra_xusb_pad *
75453d2a715SThierry Reding tegra124_ulpi_pad_probe(struct tegra_xusb_padctl *padctl,
75553d2a715SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
75653d2a715SThierry Reding 			struct device_node *np)
75753d2a715SThierry Reding {
75853d2a715SThierry Reding 	struct tegra_xusb_ulpi_pad *ulpi;
75953d2a715SThierry Reding 	struct tegra_xusb_pad *pad;
76053d2a715SThierry Reding 	int err;
76153d2a715SThierry Reding 
76253d2a715SThierry Reding 	ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL);
76353d2a715SThierry Reding 	if (!ulpi)
76453d2a715SThierry Reding 		return ERR_PTR(-ENOMEM);
76553d2a715SThierry Reding 
76653d2a715SThierry Reding 	pad = &ulpi->base;
76753d2a715SThierry Reding 	pad->ops = &tegra124_ulpi_lane_ops;
76853d2a715SThierry Reding 	pad->soc = soc;
76953d2a715SThierry Reding 
77053d2a715SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
77153d2a715SThierry Reding 	if (err < 0) {
77253d2a715SThierry Reding 		kfree(ulpi);
77353d2a715SThierry Reding 		goto out;
77453d2a715SThierry Reding 	}
77553d2a715SThierry Reding 
77653d2a715SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra124_ulpi_phy_ops);
77753d2a715SThierry Reding 	if (err < 0)
77853d2a715SThierry Reding 		goto unregister;
77953d2a715SThierry Reding 
78053d2a715SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
78153d2a715SThierry Reding 
78253d2a715SThierry Reding 	return pad;
78353d2a715SThierry Reding 
78453d2a715SThierry Reding unregister:
78553d2a715SThierry Reding 	device_unregister(&pad->dev);
78653d2a715SThierry Reding out:
78753d2a715SThierry Reding 	return ERR_PTR(err);
78853d2a715SThierry Reding }
78953d2a715SThierry Reding 
79053d2a715SThierry Reding static void tegra124_ulpi_pad_remove(struct tegra_xusb_pad *pad)
79153d2a715SThierry Reding {
79253d2a715SThierry Reding 	struct tegra_xusb_ulpi_pad *ulpi = to_ulpi_pad(pad);
79353d2a715SThierry Reding 
79453d2a715SThierry Reding 	kfree(ulpi);
79553d2a715SThierry Reding }
79653d2a715SThierry Reding 
79753d2a715SThierry Reding static const struct tegra_xusb_pad_ops tegra124_ulpi_ops = {
79853d2a715SThierry Reding 	.probe = tegra124_ulpi_pad_probe,
79953d2a715SThierry Reding 	.remove = tegra124_ulpi_pad_remove,
80053d2a715SThierry Reding };
80153d2a715SThierry Reding 
80253d2a715SThierry Reding static const struct tegra_xusb_pad_soc tegra124_ulpi_pad = {
80353d2a715SThierry Reding 	.name = "ulpi",
80453d2a715SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra124_ulpi_lanes),
80553d2a715SThierry Reding 	.lanes = tegra124_ulpi_lanes,
80653d2a715SThierry Reding 	.ops = &tegra124_ulpi_ops,
80753d2a715SThierry Reding };
80853d2a715SThierry Reding 
80953d2a715SThierry Reding static const char * const tegra124_hsic_functions[] = {
81053d2a715SThierry Reding 	"snps",
81153d2a715SThierry Reding 	"xusb",
81253d2a715SThierry Reding };
81353d2a715SThierry Reding 
81453d2a715SThierry Reding static const struct tegra_xusb_lane_soc tegra124_hsic_lanes[] = {
81553d2a715SThierry Reding 	TEGRA124_LANE("hsic-0", 0x004, 14, 0x1, hsic),
81653d2a715SThierry Reding 	TEGRA124_LANE("hsic-1", 0x004, 15, 0x1, hsic),
81753d2a715SThierry Reding };
81853d2a715SThierry Reding 
81953d2a715SThierry Reding static struct tegra_xusb_lane *
82053d2a715SThierry Reding tegra124_hsic_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
82153d2a715SThierry Reding 			 unsigned int index)
82253d2a715SThierry Reding {
82353d2a715SThierry Reding 	struct tegra_xusb_hsic_lane *hsic;
82453d2a715SThierry Reding 	int err;
82553d2a715SThierry Reding 
82653d2a715SThierry Reding 	hsic = kzalloc(sizeof(*hsic), GFP_KERNEL);
82753d2a715SThierry Reding 	if (!hsic)
82853d2a715SThierry Reding 		return ERR_PTR(-ENOMEM);
82953d2a715SThierry Reding 
83053d2a715SThierry Reding 	INIT_LIST_HEAD(&hsic->base.list);
83153d2a715SThierry Reding 	hsic->base.soc = &pad->soc->lanes[index];
83253d2a715SThierry Reding 	hsic->base.index = index;
83353d2a715SThierry Reding 	hsic->base.pad = pad;
83453d2a715SThierry Reding 	hsic->base.np = np;
83553d2a715SThierry Reding 
83653d2a715SThierry Reding 	err = tegra_xusb_lane_parse_dt(&hsic->base, np);
83753d2a715SThierry Reding 	if (err < 0) {
83853d2a715SThierry Reding 		kfree(hsic);
83953d2a715SThierry Reding 		return ERR_PTR(err);
84053d2a715SThierry Reding 	}
84153d2a715SThierry Reding 
84253d2a715SThierry Reding 	return &hsic->base;
84353d2a715SThierry Reding }
84453d2a715SThierry Reding 
84553d2a715SThierry Reding static void tegra124_hsic_lane_remove(struct tegra_xusb_lane *lane)
84653d2a715SThierry Reding {
84753d2a715SThierry Reding 	struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane);
84853d2a715SThierry Reding 
84953d2a715SThierry Reding 	kfree(hsic);
85053d2a715SThierry Reding }
85153d2a715SThierry Reding 
85253d2a715SThierry Reding static const struct tegra_xusb_lane_ops tegra124_hsic_lane_ops = {
85353d2a715SThierry Reding 	.probe = tegra124_hsic_lane_probe,
85453d2a715SThierry Reding 	.remove = tegra124_hsic_lane_remove,
85553d2a715SThierry Reding };
85653d2a715SThierry Reding 
85753d2a715SThierry Reding static int tegra124_hsic_phy_init(struct phy *phy)
85853d2a715SThierry Reding {
85953d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
86053d2a715SThierry Reding 
86153d2a715SThierry Reding 	return tegra124_xusb_padctl_enable(lane->pad->padctl);
86253d2a715SThierry Reding }
86353d2a715SThierry Reding 
86453d2a715SThierry Reding static int tegra124_hsic_phy_exit(struct phy *phy)
86553d2a715SThierry Reding {
86653d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
86753d2a715SThierry Reding 
86853d2a715SThierry Reding 	return tegra124_xusb_padctl_disable(lane->pad->padctl);
86953d2a715SThierry Reding }
87053d2a715SThierry Reding 
87153d2a715SThierry Reding static int tegra124_hsic_phy_power_on(struct phy *phy)
87253d2a715SThierry Reding {
87353d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
87453d2a715SThierry Reding 	struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane);
87553d2a715SThierry Reding 	struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad);
87653d2a715SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
87753d2a715SThierry Reding 	unsigned int index = lane->index;
87853d2a715SThierry Reding 	u32 value;
87953d2a715SThierry Reding 	int err;
88053d2a715SThierry Reding 
88153d2a715SThierry Reding 	err = regulator_enable(pad->supply);
88253d2a715SThierry Reding 	if (err)
88353d2a715SThierry Reding 		return err;
88453d2a715SThierry Reding 
88553d2a715SThierry Reding 	padctl_writel(padctl, hsic->strobe_trim,
88653d2a715SThierry Reding 		      XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL);
88753d2a715SThierry Reding 
88853d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index));
88953d2a715SThierry Reding 
89053d2a715SThierry Reding 	if (hsic->auto_term)
89153d2a715SThierry Reding 		value |= XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN;
89253d2a715SThierry Reding 	else
89353d2a715SThierry Reding 		value &= ~XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN;
89453d2a715SThierry Reding 
89553d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index));
89653d2a715SThierry Reding 
89753d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index));
89853d2a715SThierry Reding 	value &= ~((XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK <<
89953d2a715SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT) |
90053d2a715SThierry Reding 		   (XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK <<
90153d2a715SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT) |
90253d2a715SThierry Reding 		   (XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK <<
90353d2a715SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT) |
90453d2a715SThierry Reding 		   (XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK <<
90553d2a715SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT));
90653d2a715SThierry Reding 	value |= (hsic->tx_rtune_n <<
90753d2a715SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT) |
90853d2a715SThierry Reding 		(hsic->tx_rtune_p <<
90953d2a715SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT) |
91053d2a715SThierry Reding 		(hsic->tx_rslew_n <<
91153d2a715SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT) |
91253d2a715SThierry Reding 		(hsic->tx_rslew_p <<
91353d2a715SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT);
91453d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL0(index));
91553d2a715SThierry Reding 
91653d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(index));
91753d2a715SThierry Reding 	value &= ~((XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK <<
91853d2a715SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) |
91953d2a715SThierry Reding 		   (XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK <<
92053d2a715SThierry Reding 		    XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT));
92153d2a715SThierry Reding 	value |= (hsic->rx_strobe_trim <<
92253d2a715SThierry Reding 		  XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) |
92353d2a715SThierry Reding 		(hsic->rx_data_trim <<
92453d2a715SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT);
92553d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL2(index));
92653d2a715SThierry Reding 
92753d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index));
92853d2a715SThierry Reding 	value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_RPD_STROBE |
92953d2a715SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL1_RPU_DATA |
93053d2a715SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX |
93153d2a715SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI |
93253d2a715SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX |
93353d2a715SThierry Reding 		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX);
93453d2a715SThierry Reding 	value |= XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA |
93553d2a715SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE;
93653d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index));
93753d2a715SThierry Reding 
93853d2a715SThierry Reding 	return 0;
93953d2a715SThierry Reding }
94053d2a715SThierry Reding 
94153d2a715SThierry Reding static int tegra124_hsic_phy_power_off(struct phy *phy)
94253d2a715SThierry Reding {
94353d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
94453d2a715SThierry Reding 	struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad);
94553d2a715SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
94653d2a715SThierry Reding 	unsigned int index = lane->index;
94753d2a715SThierry Reding 	u32 value;
94853d2a715SThierry Reding 
94953d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index));
95053d2a715SThierry Reding 	value |= XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX |
95153d2a715SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI |
95253d2a715SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX |
95353d2a715SThierry Reding 		 XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX;
95453d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index));
95553d2a715SThierry Reding 
95653d2a715SThierry Reding 	regulator_disable(pad->supply);
95753d2a715SThierry Reding 
95853d2a715SThierry Reding 	return 0;
95953d2a715SThierry Reding }
96053d2a715SThierry Reding 
96153d2a715SThierry Reding static const struct phy_ops tegra124_hsic_phy_ops = {
96253d2a715SThierry Reding 	.init = tegra124_hsic_phy_init,
96353d2a715SThierry Reding 	.exit = tegra124_hsic_phy_exit,
96453d2a715SThierry Reding 	.power_on = tegra124_hsic_phy_power_on,
96553d2a715SThierry Reding 	.power_off = tegra124_hsic_phy_power_off,
96653d2a715SThierry Reding 	.owner = THIS_MODULE,
96753d2a715SThierry Reding };
96853d2a715SThierry Reding 
96953d2a715SThierry Reding static struct tegra_xusb_pad *
97053d2a715SThierry Reding tegra124_hsic_pad_probe(struct tegra_xusb_padctl *padctl,
97153d2a715SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
97253d2a715SThierry Reding 			struct device_node *np)
97353d2a715SThierry Reding {
97453d2a715SThierry Reding 	struct tegra_xusb_hsic_pad *hsic;
97553d2a715SThierry Reding 	struct tegra_xusb_pad *pad;
97653d2a715SThierry Reding 	int err;
97753d2a715SThierry Reding 
97853d2a715SThierry Reding 	hsic = kzalloc(sizeof(*hsic), GFP_KERNEL);
97953d2a715SThierry Reding 	if (!hsic)
98053d2a715SThierry Reding 		return ERR_PTR(-ENOMEM);
98153d2a715SThierry Reding 
98253d2a715SThierry Reding 	pad = &hsic->base;
98353d2a715SThierry Reding 	pad->ops = &tegra124_hsic_lane_ops;
98453d2a715SThierry Reding 	pad->soc = soc;
98553d2a715SThierry Reding 
98653d2a715SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
98753d2a715SThierry Reding 	if (err < 0) {
98853d2a715SThierry Reding 		kfree(hsic);
98953d2a715SThierry Reding 		goto out;
99053d2a715SThierry Reding 	}
99153d2a715SThierry Reding 
99253d2a715SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra124_hsic_phy_ops);
99353d2a715SThierry Reding 	if (err < 0)
99453d2a715SThierry Reding 		goto unregister;
99553d2a715SThierry Reding 
99653d2a715SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
99753d2a715SThierry Reding 
99853d2a715SThierry Reding 	return pad;
99953d2a715SThierry Reding 
100053d2a715SThierry Reding unregister:
100153d2a715SThierry Reding 	device_unregister(&pad->dev);
100253d2a715SThierry Reding out:
100353d2a715SThierry Reding 	return ERR_PTR(err);
100453d2a715SThierry Reding }
100553d2a715SThierry Reding 
100653d2a715SThierry Reding static void tegra124_hsic_pad_remove(struct tegra_xusb_pad *pad)
100753d2a715SThierry Reding {
100853d2a715SThierry Reding 	struct tegra_xusb_hsic_pad *hsic = to_hsic_pad(pad);
100953d2a715SThierry Reding 
101053d2a715SThierry Reding 	kfree(hsic);
101153d2a715SThierry Reding }
101253d2a715SThierry Reding 
101353d2a715SThierry Reding static const struct tegra_xusb_pad_ops tegra124_hsic_ops = {
101453d2a715SThierry Reding 	.probe = tegra124_hsic_pad_probe,
101553d2a715SThierry Reding 	.remove = tegra124_hsic_pad_remove,
101653d2a715SThierry Reding };
101753d2a715SThierry Reding 
101853d2a715SThierry Reding static const struct tegra_xusb_pad_soc tegra124_hsic_pad = {
101953d2a715SThierry Reding 	.name = "hsic",
102053d2a715SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra124_hsic_lanes),
102153d2a715SThierry Reding 	.lanes = tegra124_hsic_lanes,
102253d2a715SThierry Reding 	.ops = &tegra124_hsic_ops,
102353d2a715SThierry Reding };
102453d2a715SThierry Reding 
102553d2a715SThierry Reding static const char * const tegra124_pcie_functions[] = {
102653d2a715SThierry Reding 	"pcie",
102753d2a715SThierry Reding 	"usb3-ss",
102853d2a715SThierry Reding 	"sata",
102953d2a715SThierry Reding };
103053d2a715SThierry Reding 
103153d2a715SThierry Reding static const struct tegra_xusb_lane_soc tegra124_pcie_lanes[] = {
103253d2a715SThierry Reding 	TEGRA124_LANE("pcie-0", 0x134, 16, 0x3, pcie),
103353d2a715SThierry Reding 	TEGRA124_LANE("pcie-1", 0x134, 18, 0x3, pcie),
103453d2a715SThierry Reding 	TEGRA124_LANE("pcie-2", 0x134, 20, 0x3, pcie),
103553d2a715SThierry Reding 	TEGRA124_LANE("pcie-3", 0x134, 22, 0x3, pcie),
103653d2a715SThierry Reding 	TEGRA124_LANE("pcie-4", 0x134, 24, 0x3, pcie),
103753d2a715SThierry Reding };
103853d2a715SThierry Reding 
103953d2a715SThierry Reding static struct tegra_xusb_lane *
104053d2a715SThierry Reding tegra124_pcie_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
104153d2a715SThierry Reding 			 unsigned int index)
104253d2a715SThierry Reding {
104353d2a715SThierry Reding 	struct tegra_xusb_pcie_lane *pcie;
104453d2a715SThierry Reding 	int err;
104553d2a715SThierry Reding 
104653d2a715SThierry Reding 	pcie = kzalloc(sizeof(*pcie), GFP_KERNEL);
104753d2a715SThierry Reding 	if (!pcie)
104853d2a715SThierry Reding 		return ERR_PTR(-ENOMEM);
104953d2a715SThierry Reding 
105053d2a715SThierry Reding 	INIT_LIST_HEAD(&pcie->base.list);
105153d2a715SThierry Reding 	pcie->base.soc = &pad->soc->lanes[index];
105253d2a715SThierry Reding 	pcie->base.index = index;
105353d2a715SThierry Reding 	pcie->base.pad = pad;
105453d2a715SThierry Reding 	pcie->base.np = np;
105553d2a715SThierry Reding 
105653d2a715SThierry Reding 	err = tegra_xusb_lane_parse_dt(&pcie->base, np);
105753d2a715SThierry Reding 	if (err < 0) {
105853d2a715SThierry Reding 		kfree(pcie);
105953d2a715SThierry Reding 		return ERR_PTR(err);
106053d2a715SThierry Reding 	}
106153d2a715SThierry Reding 
106253d2a715SThierry Reding 	return &pcie->base;
106353d2a715SThierry Reding }
106453d2a715SThierry Reding 
106553d2a715SThierry Reding static void tegra124_pcie_lane_remove(struct tegra_xusb_lane *lane)
106653d2a715SThierry Reding {
106753d2a715SThierry Reding 	struct tegra_xusb_pcie_lane *pcie = to_pcie_lane(lane);
106853d2a715SThierry Reding 
106953d2a715SThierry Reding 	kfree(pcie);
107053d2a715SThierry Reding }
107153d2a715SThierry Reding 
107253d2a715SThierry Reding static const struct tegra_xusb_lane_ops tegra124_pcie_lane_ops = {
107353d2a715SThierry Reding 	.probe = tegra124_pcie_lane_probe,
107453d2a715SThierry Reding 	.remove = tegra124_pcie_lane_remove,
107553d2a715SThierry Reding };
107653d2a715SThierry Reding 
107753d2a715SThierry Reding static int tegra124_pcie_phy_init(struct phy *phy)
107853d2a715SThierry Reding {
107953d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
108053d2a715SThierry Reding 
108153d2a715SThierry Reding 	return tegra124_xusb_padctl_enable(lane->pad->padctl);
108253d2a715SThierry Reding }
108353d2a715SThierry Reding 
108453d2a715SThierry Reding static int tegra124_pcie_phy_exit(struct phy *phy)
108553d2a715SThierry Reding {
108653d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
108753d2a715SThierry Reding 
108853d2a715SThierry Reding 	return tegra124_xusb_padctl_disable(lane->pad->padctl);
108953d2a715SThierry Reding }
109053d2a715SThierry Reding 
109153d2a715SThierry Reding static int tegra124_pcie_phy_power_on(struct phy *phy)
109253d2a715SThierry Reding {
109353d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
109453d2a715SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
109553d2a715SThierry Reding 	unsigned long timeout;
109653d2a715SThierry Reding 	int err = -ETIMEDOUT;
109753d2a715SThierry Reding 	u32 value;
109853d2a715SThierry Reding 
109953d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
110053d2a715SThierry Reding 	value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK;
110153d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
110253d2a715SThierry Reding 
110353d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
110453d2a715SThierry Reding 	value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN |
110553d2a715SThierry Reding 		 XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN |
110653d2a715SThierry Reding 		 XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL;
110753d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
110853d2a715SThierry Reding 
110953d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
111053d2a715SThierry Reding 	value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST;
111153d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
111253d2a715SThierry Reding 
111353d2a715SThierry Reding 	timeout = jiffies + msecs_to_jiffies(50);
111453d2a715SThierry Reding 
111553d2a715SThierry Reding 	while (time_before(jiffies, timeout)) {
111653d2a715SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
111753d2a715SThierry Reding 		if (value & XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET) {
111853d2a715SThierry Reding 			err = 0;
111953d2a715SThierry Reding 			break;
112053d2a715SThierry Reding 		}
112153d2a715SThierry Reding 
112253d2a715SThierry Reding 		usleep_range(100, 200);
112353d2a715SThierry Reding 	}
112453d2a715SThierry Reding 
112553d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
112653d2a715SThierry Reding 	value |= XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->index);
112753d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
112853d2a715SThierry Reding 
112953d2a715SThierry Reding 	return err;
113053d2a715SThierry Reding }
113153d2a715SThierry Reding 
113253d2a715SThierry Reding static int tegra124_pcie_phy_power_off(struct phy *phy)
113353d2a715SThierry Reding {
113453d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
113553d2a715SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
113653d2a715SThierry Reding 	u32 value;
113753d2a715SThierry Reding 
113853d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
113953d2a715SThierry Reding 	value &= ~XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->index);
114053d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
114153d2a715SThierry Reding 
114253d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
114353d2a715SThierry Reding 	value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST;
114453d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
114553d2a715SThierry Reding 
114653d2a715SThierry Reding 	return 0;
114753d2a715SThierry Reding }
114853d2a715SThierry Reding 
114953d2a715SThierry Reding static const struct phy_ops tegra124_pcie_phy_ops = {
115053d2a715SThierry Reding 	.init = tegra124_pcie_phy_init,
115153d2a715SThierry Reding 	.exit = tegra124_pcie_phy_exit,
115253d2a715SThierry Reding 	.power_on = tegra124_pcie_phy_power_on,
115353d2a715SThierry Reding 	.power_off = tegra124_pcie_phy_power_off,
115453d2a715SThierry Reding 	.owner = THIS_MODULE,
115553d2a715SThierry Reding };
115653d2a715SThierry Reding 
115753d2a715SThierry Reding static struct tegra_xusb_pad *
115853d2a715SThierry Reding tegra124_pcie_pad_probe(struct tegra_xusb_padctl *padctl,
115953d2a715SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
116053d2a715SThierry Reding 			struct device_node *np)
116153d2a715SThierry Reding {
116253d2a715SThierry Reding 	struct tegra_xusb_pcie_pad *pcie;
116353d2a715SThierry Reding 	struct tegra_xusb_pad *pad;
116453d2a715SThierry Reding 	int err;
116553d2a715SThierry Reding 
116653d2a715SThierry Reding 	pcie = kzalloc(sizeof(*pcie), GFP_KERNEL);
116753d2a715SThierry Reding 	if (!pcie)
116853d2a715SThierry Reding 		return ERR_PTR(-ENOMEM);
116953d2a715SThierry Reding 
117053d2a715SThierry Reding 	pad = &pcie->base;
117153d2a715SThierry Reding 	pad->ops = &tegra124_pcie_lane_ops;
117253d2a715SThierry Reding 	pad->soc = soc;
117353d2a715SThierry Reding 
117453d2a715SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
117553d2a715SThierry Reding 	if (err < 0) {
117653d2a715SThierry Reding 		kfree(pcie);
117753d2a715SThierry Reding 		goto out;
117853d2a715SThierry Reding 	}
117953d2a715SThierry Reding 
118053d2a715SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra124_pcie_phy_ops);
118153d2a715SThierry Reding 	if (err < 0)
118253d2a715SThierry Reding 		goto unregister;
118353d2a715SThierry Reding 
118453d2a715SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
118553d2a715SThierry Reding 
118653d2a715SThierry Reding 	return pad;
118753d2a715SThierry Reding 
118853d2a715SThierry Reding unregister:
118953d2a715SThierry Reding 	device_unregister(&pad->dev);
119053d2a715SThierry Reding out:
119153d2a715SThierry Reding 	return ERR_PTR(err);
119253d2a715SThierry Reding }
119353d2a715SThierry Reding 
119453d2a715SThierry Reding static void tegra124_pcie_pad_remove(struct tegra_xusb_pad *pad)
119553d2a715SThierry Reding {
119653d2a715SThierry Reding 	struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(pad);
119753d2a715SThierry Reding 
119853d2a715SThierry Reding 	kfree(pcie);
119953d2a715SThierry Reding }
120053d2a715SThierry Reding 
120153d2a715SThierry Reding static const struct tegra_xusb_pad_ops tegra124_pcie_ops = {
120253d2a715SThierry Reding 	.probe = tegra124_pcie_pad_probe,
120353d2a715SThierry Reding 	.remove = tegra124_pcie_pad_remove,
120453d2a715SThierry Reding };
120553d2a715SThierry Reding 
120653d2a715SThierry Reding static const struct tegra_xusb_pad_soc tegra124_pcie_pad = {
120753d2a715SThierry Reding 	.name = "pcie",
120853d2a715SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra124_pcie_lanes),
120953d2a715SThierry Reding 	.lanes = tegra124_pcie_lanes,
121053d2a715SThierry Reding 	.ops = &tegra124_pcie_ops,
121153d2a715SThierry Reding };
121253d2a715SThierry Reding 
121353d2a715SThierry Reding static const struct tegra_xusb_lane_soc tegra124_sata_lanes[] = {
121453d2a715SThierry Reding 	TEGRA124_LANE("sata-0", 0x134, 26, 0x3, pcie),
121553d2a715SThierry Reding };
121653d2a715SThierry Reding 
121753d2a715SThierry Reding static struct tegra_xusb_lane *
121853d2a715SThierry Reding tegra124_sata_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np,
121953d2a715SThierry Reding 			 unsigned int index)
122053d2a715SThierry Reding {
122153d2a715SThierry Reding 	struct tegra_xusb_sata_lane *sata;
122253d2a715SThierry Reding 	int err;
122353d2a715SThierry Reding 
122453d2a715SThierry Reding 	sata = kzalloc(sizeof(*sata), GFP_KERNEL);
122553d2a715SThierry Reding 	if (!sata)
122653d2a715SThierry Reding 		return ERR_PTR(-ENOMEM);
122753d2a715SThierry Reding 
122853d2a715SThierry Reding 	INIT_LIST_HEAD(&sata->base.list);
122953d2a715SThierry Reding 	sata->base.soc = &pad->soc->lanes[index];
123053d2a715SThierry Reding 	sata->base.index = index;
123153d2a715SThierry Reding 	sata->base.pad = pad;
123253d2a715SThierry Reding 	sata->base.np = np;
123353d2a715SThierry Reding 
123453d2a715SThierry Reding 	err = tegra_xusb_lane_parse_dt(&sata->base, np);
123553d2a715SThierry Reding 	if (err < 0) {
123653d2a715SThierry Reding 		kfree(sata);
123753d2a715SThierry Reding 		return ERR_PTR(err);
123853d2a715SThierry Reding 	}
123953d2a715SThierry Reding 
124053d2a715SThierry Reding 	return &sata->base;
124153d2a715SThierry Reding }
124253d2a715SThierry Reding 
124353d2a715SThierry Reding static void tegra124_sata_lane_remove(struct tegra_xusb_lane *lane)
124453d2a715SThierry Reding {
124553d2a715SThierry Reding 	struct tegra_xusb_sata_lane *sata = to_sata_lane(lane);
124653d2a715SThierry Reding 
124753d2a715SThierry Reding 	kfree(sata);
124853d2a715SThierry Reding }
124953d2a715SThierry Reding 
125053d2a715SThierry Reding static const struct tegra_xusb_lane_ops tegra124_sata_lane_ops = {
125153d2a715SThierry Reding 	.probe = tegra124_sata_lane_probe,
125253d2a715SThierry Reding 	.remove = tegra124_sata_lane_remove,
125353d2a715SThierry Reding };
125453d2a715SThierry Reding 
125553d2a715SThierry Reding static int tegra124_sata_phy_init(struct phy *phy)
125653d2a715SThierry Reding {
125753d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
125853d2a715SThierry Reding 
125953d2a715SThierry Reding 	return tegra124_xusb_padctl_enable(lane->pad->padctl);
126053d2a715SThierry Reding }
126153d2a715SThierry Reding 
126253d2a715SThierry Reding static int tegra124_sata_phy_exit(struct phy *phy)
126353d2a715SThierry Reding {
126453d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
126553d2a715SThierry Reding 
126653d2a715SThierry Reding 	return tegra124_xusb_padctl_disable(lane->pad->padctl);
126753d2a715SThierry Reding }
126853d2a715SThierry Reding 
126953d2a715SThierry Reding static int tegra124_sata_phy_power_on(struct phy *phy)
127053d2a715SThierry Reding {
127153d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
127253d2a715SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
127353d2a715SThierry Reding 	unsigned long timeout;
127453d2a715SThierry Reding 	int err = -ETIMEDOUT;
127553d2a715SThierry Reding 	u32 value;
127653d2a715SThierry Reding 
127753d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
127853d2a715SThierry Reding 	value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
127953d2a715SThierry Reding 	value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ;
128053d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
128153d2a715SThierry Reding 
128253d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
128353d2a715SThierry Reding 	value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
128453d2a715SThierry Reding 	value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ;
128553d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
128653d2a715SThierry Reding 
128753d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
128853d2a715SThierry Reding 	value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE;
128953d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
129053d2a715SThierry Reding 
129153d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
129253d2a715SThierry Reding 	value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST;
129353d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
129453d2a715SThierry Reding 
129553d2a715SThierry Reding 	timeout = jiffies + msecs_to_jiffies(50);
129653d2a715SThierry Reding 
129753d2a715SThierry Reding 	while (time_before(jiffies, timeout)) {
129853d2a715SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
129953d2a715SThierry Reding 		if (value & XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET) {
130053d2a715SThierry Reding 			err = 0;
130153d2a715SThierry Reding 			break;
130253d2a715SThierry Reding 		}
130353d2a715SThierry Reding 
130453d2a715SThierry Reding 		usleep_range(100, 200);
130553d2a715SThierry Reding 	}
130653d2a715SThierry Reding 
130753d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
130853d2a715SThierry Reding 	value |= XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->index);
130953d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
131053d2a715SThierry Reding 
131153d2a715SThierry Reding 	return err;
131253d2a715SThierry Reding }
131353d2a715SThierry Reding 
131453d2a715SThierry Reding static int tegra124_sata_phy_power_off(struct phy *phy)
131553d2a715SThierry Reding {
131653d2a715SThierry Reding 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
131753d2a715SThierry Reding 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
131853d2a715SThierry Reding 	u32 value;
131953d2a715SThierry Reding 
132053d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
132153d2a715SThierry Reding 	value &= ~XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(lane->index);
132253d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX);
132353d2a715SThierry Reding 
132453d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
132553d2a715SThierry Reding 	value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST;
132653d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
132753d2a715SThierry Reding 
132853d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
132953d2a715SThierry Reding 	value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE;
133053d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
133153d2a715SThierry Reding 
133253d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
133353d2a715SThierry Reding 	value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
133453d2a715SThierry Reding 	value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ;
133553d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
133653d2a715SThierry Reding 
133753d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
133853d2a715SThierry Reding 	value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
133953d2a715SThierry Reding 	value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ;
134053d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
134153d2a715SThierry Reding 
134253d2a715SThierry Reding 	return 0;
134353d2a715SThierry Reding }
134453d2a715SThierry Reding 
134553d2a715SThierry Reding static const struct phy_ops tegra124_sata_phy_ops = {
134653d2a715SThierry Reding 	.init = tegra124_sata_phy_init,
134753d2a715SThierry Reding 	.exit = tegra124_sata_phy_exit,
134853d2a715SThierry Reding 	.power_on = tegra124_sata_phy_power_on,
134953d2a715SThierry Reding 	.power_off = tegra124_sata_phy_power_off,
135053d2a715SThierry Reding 	.owner = THIS_MODULE,
135153d2a715SThierry Reding };
135253d2a715SThierry Reding 
135353d2a715SThierry Reding static struct tegra_xusb_pad *
135453d2a715SThierry Reding tegra124_sata_pad_probe(struct tegra_xusb_padctl *padctl,
135553d2a715SThierry Reding 			const struct tegra_xusb_pad_soc *soc,
135653d2a715SThierry Reding 			struct device_node *np)
135753d2a715SThierry Reding {
135853d2a715SThierry Reding 	struct tegra_xusb_sata_pad *sata;
135953d2a715SThierry Reding 	struct tegra_xusb_pad *pad;
136053d2a715SThierry Reding 	int err;
136153d2a715SThierry Reding 
136253d2a715SThierry Reding 	sata = kzalloc(sizeof(*sata), GFP_KERNEL);
136353d2a715SThierry Reding 	if (!sata)
136453d2a715SThierry Reding 		return ERR_PTR(-ENOMEM);
136553d2a715SThierry Reding 
136653d2a715SThierry Reding 	pad = &sata->base;
136753d2a715SThierry Reding 	pad->ops = &tegra124_sata_lane_ops;
136853d2a715SThierry Reding 	pad->soc = soc;
136953d2a715SThierry Reding 
137053d2a715SThierry Reding 	err = tegra_xusb_pad_init(pad, padctl, np);
137153d2a715SThierry Reding 	if (err < 0) {
137253d2a715SThierry Reding 		kfree(sata);
137353d2a715SThierry Reding 		goto out;
137453d2a715SThierry Reding 	}
137553d2a715SThierry Reding 
137653d2a715SThierry Reding 	err = tegra_xusb_pad_register(pad, &tegra124_sata_phy_ops);
137753d2a715SThierry Reding 	if (err < 0)
137853d2a715SThierry Reding 		goto unregister;
137953d2a715SThierry Reding 
138053d2a715SThierry Reding 	dev_set_drvdata(&pad->dev, pad);
138153d2a715SThierry Reding 
138253d2a715SThierry Reding 	return pad;
138353d2a715SThierry Reding 
138453d2a715SThierry Reding unregister:
138553d2a715SThierry Reding 	device_unregister(&pad->dev);
138653d2a715SThierry Reding out:
138753d2a715SThierry Reding 	return ERR_PTR(err);
138853d2a715SThierry Reding }
138953d2a715SThierry Reding 
139053d2a715SThierry Reding static void tegra124_sata_pad_remove(struct tegra_xusb_pad *pad)
139153d2a715SThierry Reding {
139253d2a715SThierry Reding 	struct tegra_xusb_sata_pad *sata = to_sata_pad(pad);
139353d2a715SThierry Reding 
139453d2a715SThierry Reding 	kfree(sata);
139553d2a715SThierry Reding }
139653d2a715SThierry Reding 
139753d2a715SThierry Reding static const struct tegra_xusb_pad_ops tegra124_sata_ops = {
139853d2a715SThierry Reding 	.probe = tegra124_sata_pad_probe,
139953d2a715SThierry Reding 	.remove = tegra124_sata_pad_remove,
140053d2a715SThierry Reding };
140153d2a715SThierry Reding 
140253d2a715SThierry Reding static const struct tegra_xusb_pad_soc tegra124_sata_pad = {
140353d2a715SThierry Reding 	.name = "sata",
140453d2a715SThierry Reding 	.num_lanes = ARRAY_SIZE(tegra124_sata_lanes),
140553d2a715SThierry Reding 	.lanes = tegra124_sata_lanes,
140653d2a715SThierry Reding 	.ops = &tegra124_sata_ops,
140753d2a715SThierry Reding };
140853d2a715SThierry Reding 
140953d2a715SThierry Reding static const struct tegra_xusb_pad_soc *tegra124_pads[] = {
141053d2a715SThierry Reding 	&tegra124_usb2_pad,
141153d2a715SThierry Reding 	&tegra124_ulpi_pad,
141253d2a715SThierry Reding 	&tegra124_hsic_pad,
141353d2a715SThierry Reding 	&tegra124_pcie_pad,
141453d2a715SThierry Reding 	&tegra124_sata_pad,
141553d2a715SThierry Reding };
141653d2a715SThierry Reding 
141753d2a715SThierry Reding static int tegra124_usb2_port_enable(struct tegra_xusb_port *port)
141853d2a715SThierry Reding {
141953d2a715SThierry Reding 	return 0;
142053d2a715SThierry Reding }
142153d2a715SThierry Reding 
142253d2a715SThierry Reding static void tegra124_usb2_port_disable(struct tegra_xusb_port *port)
142353d2a715SThierry Reding {
142453d2a715SThierry Reding }
142553d2a715SThierry Reding 
142653d2a715SThierry Reding static struct tegra_xusb_lane *
142753d2a715SThierry Reding tegra124_usb2_port_map(struct tegra_xusb_port *port)
142853d2a715SThierry Reding {
142953d2a715SThierry Reding 	return tegra_xusb_find_lane(port->padctl, "usb2", port->index);
143053d2a715SThierry Reding }
143153d2a715SThierry Reding 
143253d2a715SThierry Reding static const struct tegra_xusb_port_ops tegra124_usb2_port_ops = {
143353d2a715SThierry Reding 	.enable = tegra124_usb2_port_enable,
143453d2a715SThierry Reding 	.disable = tegra124_usb2_port_disable,
143553d2a715SThierry Reding 	.map = tegra124_usb2_port_map,
143653d2a715SThierry Reding };
143753d2a715SThierry Reding 
143853d2a715SThierry Reding static int tegra124_ulpi_port_enable(struct tegra_xusb_port *port)
143953d2a715SThierry Reding {
144053d2a715SThierry Reding 	return 0;
144153d2a715SThierry Reding }
144253d2a715SThierry Reding 
144353d2a715SThierry Reding static void tegra124_ulpi_port_disable(struct tegra_xusb_port *port)
144453d2a715SThierry Reding {
144553d2a715SThierry Reding }
144653d2a715SThierry Reding 
144753d2a715SThierry Reding static struct tegra_xusb_lane *
144853d2a715SThierry Reding tegra124_ulpi_port_map(struct tegra_xusb_port *port)
144953d2a715SThierry Reding {
145053d2a715SThierry Reding 	return tegra_xusb_find_lane(port->padctl, "ulpi", port->index);
145153d2a715SThierry Reding }
145253d2a715SThierry Reding 
145353d2a715SThierry Reding static const struct tegra_xusb_port_ops tegra124_ulpi_port_ops = {
145453d2a715SThierry Reding 	.enable = tegra124_ulpi_port_enable,
145553d2a715SThierry Reding 	.disable = tegra124_ulpi_port_disable,
145653d2a715SThierry Reding 	.map = tegra124_ulpi_port_map,
145753d2a715SThierry Reding };
145853d2a715SThierry Reding 
145953d2a715SThierry Reding static int tegra124_hsic_port_enable(struct tegra_xusb_port *port)
146053d2a715SThierry Reding {
146153d2a715SThierry Reding 	return 0;
146253d2a715SThierry Reding }
146353d2a715SThierry Reding 
146453d2a715SThierry Reding static void tegra124_hsic_port_disable(struct tegra_xusb_port *port)
146553d2a715SThierry Reding {
146653d2a715SThierry Reding }
146753d2a715SThierry Reding 
146853d2a715SThierry Reding static struct tegra_xusb_lane *
146953d2a715SThierry Reding tegra124_hsic_port_map(struct tegra_xusb_port *port)
147053d2a715SThierry Reding {
147153d2a715SThierry Reding 	return tegra_xusb_find_lane(port->padctl, "hsic", port->index);
147253d2a715SThierry Reding }
147353d2a715SThierry Reding 
147453d2a715SThierry Reding static const struct tegra_xusb_port_ops tegra124_hsic_port_ops = {
147553d2a715SThierry Reding 	.enable = tegra124_hsic_port_enable,
147653d2a715SThierry Reding 	.disable = tegra124_hsic_port_disable,
147753d2a715SThierry Reding 	.map = tegra124_hsic_port_map,
147853d2a715SThierry Reding };
147953d2a715SThierry Reding 
148053d2a715SThierry Reding static int tegra124_usb3_port_enable(struct tegra_xusb_port *port)
148153d2a715SThierry Reding {
148253d2a715SThierry Reding 	struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
148353d2a715SThierry Reding 	struct tegra_xusb_padctl *padctl = port->padctl;
148453d2a715SThierry Reding 	struct tegra_xusb_lane *lane = usb3->base.lane;
148553d2a715SThierry Reding 	unsigned int index = port->index, offset;
148653d2a715SThierry Reding 	u32 value;
148753d2a715SThierry Reding 
148853d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
148953d2a715SThierry Reding 
149053d2a715SThierry Reding 	if (!usb3->internal)
149153d2a715SThierry Reding 		value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index);
149253d2a715SThierry Reding 	else
149353d2a715SThierry Reding 		value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index);
149453d2a715SThierry Reding 
149553d2a715SThierry Reding 	value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(index);
149653d2a715SThierry Reding 	value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(index, usb3->port);
149753d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);
149853d2a715SThierry Reding 
149953d2a715SThierry Reding 	/*
150053d2a715SThierry Reding 	 * TODO: move this code into the PCIe/SATA PHY ->power_on() callbacks
150153d2a715SThierry Reding 	 * and conditionalize based on mux function? This seems to work, but
150253d2a715SThierry Reding 	 * might not be the exact proper sequence.
150353d2a715SThierry Reding 	 */
150453d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(index));
150553d2a715SThierry Reding 	value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK <<
150653d2a715SThierry Reding 		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
150753d2a715SThierry Reding 		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK <<
150853d2a715SThierry Reding 		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) |
150953d2a715SThierry Reding 		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK <<
151053d2a715SThierry Reding 		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT));
151153d2a715SThierry Reding 	value |= (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_VAL <<
151253d2a715SThierry Reding 		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
151353d2a715SThierry Reding 		 (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_VAL <<
151453d2a715SThierry Reding 		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT) |
151553d2a715SThierry Reding 		 (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_VAL <<
151653d2a715SThierry Reding 		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT);
151753d2a715SThierry Reding 
151853d2a715SThierry Reding 	if (usb3->context_saved) {
151953d2a715SThierry Reding 		value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK <<
152053d2a715SThierry Reding 			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
152153d2a715SThierry Reding 			   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK <<
152253d2a715SThierry Reding 			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT));
152353d2a715SThierry Reding 		value |= (usb3->ctle_g <<
152453d2a715SThierry Reding 			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
152553d2a715SThierry Reding 			 (usb3->ctle_z <<
152653d2a715SThierry Reding 			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT);
152753d2a715SThierry Reding 	}
152853d2a715SThierry Reding 
152953d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(index));
153053d2a715SThierry Reding 
153153d2a715SThierry Reding 	value = XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_VAL;
153253d2a715SThierry Reding 
153353d2a715SThierry Reding 	if (usb3->context_saved) {
153453d2a715SThierry Reding 		value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK <<
153553d2a715SThierry Reding 			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
153653d2a715SThierry Reding 			   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK <<
153753d2a715SThierry Reding 			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT));
153853d2a715SThierry Reding 		value |= (usb3->tap1 <<
153953d2a715SThierry Reding 			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
154053d2a715SThierry Reding 			 (usb3->amp <<
154153d2a715SThierry Reding 			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT);
154253d2a715SThierry Reding 	}
154353d2a715SThierry Reding 
154453d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(index));
154553d2a715SThierry Reding 
154653d2a715SThierry Reding 	if (lane->pad == padctl->pcie)
154753d2a715SThierry Reding 		offset = XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL2(lane->index);
154853d2a715SThierry Reding 	else
154953d2a715SThierry Reding 		offset = XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2;
155053d2a715SThierry Reding 
155153d2a715SThierry Reding 	value = padctl_readl(padctl, offset);
155253d2a715SThierry Reding 	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_MASK <<
155353d2a715SThierry Reding 		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT);
155453d2a715SThierry Reding 	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_VAL <<
155553d2a715SThierry Reding 		XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT;
155653d2a715SThierry Reding 	padctl_writel(padctl, value, offset);
155753d2a715SThierry Reding 
155853d2a715SThierry Reding 	if (lane->pad == padctl->pcie)
155953d2a715SThierry Reding 		offset = XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL5(lane->index);
156053d2a715SThierry Reding 	else
156153d2a715SThierry Reding 		offset = XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5;
156253d2a715SThierry Reding 
156353d2a715SThierry Reding 	value = padctl_readl(padctl, offset);
156453d2a715SThierry Reding 	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL5_RX_QEYE_EN;
156553d2a715SThierry Reding 	padctl_writel(padctl, value, offset);
156653d2a715SThierry Reding 
156753d2a715SThierry Reding 	/* Enable SATA PHY when SATA lane is used */
156853d2a715SThierry Reding 	if (lane->pad == padctl->sata) {
156953d2a715SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
157053d2a715SThierry Reding 		value &= ~(XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_MASK <<
157153d2a715SThierry Reding 			   XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_SHIFT);
157253d2a715SThierry Reding 		value |= 0x2 <<
157353d2a715SThierry Reding 			XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_SHIFT;
157453d2a715SThierry Reding 		padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
157553d2a715SThierry Reding 
157653d2a715SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL2);
157753d2a715SThierry Reding 		value &= ~((XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_MASK <<
157853d2a715SThierry Reding 			    XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_SHIFT) |
157953d2a715SThierry Reding 			   (XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_MASK <<
158053d2a715SThierry Reding 			    XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_SHIFT) |
158153d2a715SThierry Reding 			   (XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_MASK <<
158253d2a715SThierry Reding 			    XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_SHIFT) |
158353d2a715SThierry Reding 			   XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TCLKOUT_EN);
158453d2a715SThierry Reding 		value |= (0x7 <<
158553d2a715SThierry Reding 			  XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_SHIFT) |
158653d2a715SThierry Reding 			 (0x8 <<
158753d2a715SThierry Reding 			  XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_SHIFT) |
158853d2a715SThierry Reding 			 (0x8 <<
158953d2a715SThierry Reding 			  XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_SHIFT) |
159053d2a715SThierry Reding 			 XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TXCLKREF_SEL;
159153d2a715SThierry Reding 		padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL2);
159253d2a715SThierry Reding 
159353d2a715SThierry Reding 		value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL3);
159453d2a715SThierry Reding 		value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL3_RCAL_BYPASS;
159553d2a715SThierry Reding 		padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL3);
159653d2a715SThierry Reding 	}
159753d2a715SThierry Reding 
159853d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
159953d2a715SThierry Reding 	value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(index);
160053d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
160153d2a715SThierry Reding 
160253d2a715SThierry Reding 	usleep_range(100, 200);
160353d2a715SThierry Reding 
160453d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
160553d2a715SThierry Reding 	value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(index);
160653d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
160753d2a715SThierry Reding 
160853d2a715SThierry Reding 	usleep_range(100, 200);
160953d2a715SThierry Reding 
161053d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
161153d2a715SThierry Reding 	value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN(index);
161253d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
161353d2a715SThierry Reding 
1614e4d5973fSVivek Gautam 	return 0;
161553d2a715SThierry Reding }
161653d2a715SThierry Reding 
161753d2a715SThierry Reding static void tegra124_usb3_port_disable(struct tegra_xusb_port *port)
161853d2a715SThierry Reding {
161953d2a715SThierry Reding 	struct tegra_xusb_padctl *padctl = port->padctl;
162053d2a715SThierry Reding 	u32 value;
162153d2a715SThierry Reding 
162253d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
162353d2a715SThierry Reding 	value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port->index);
162453d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
162553d2a715SThierry Reding 
162653d2a715SThierry Reding 	usleep_range(100, 200);
162753d2a715SThierry Reding 
162853d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
162953d2a715SThierry Reding 	value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN(port->index);
163053d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
163153d2a715SThierry Reding 
163253d2a715SThierry Reding 	usleep_range(250, 350);
163353d2a715SThierry Reding 
163453d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
163553d2a715SThierry Reding 	value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(port->index);
163653d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
163753d2a715SThierry Reding 
163853d2a715SThierry Reding 	value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
163953d2a715SThierry Reding 	value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(port->index);
164053d2a715SThierry Reding 	value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(port->index, 0x7);
164153d2a715SThierry Reding 	padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP);
164253d2a715SThierry Reding }
164353d2a715SThierry Reding 
164453d2a715SThierry Reding static const struct tegra_xusb_lane_map tegra124_usb3_map[] = {
164553d2a715SThierry Reding 	{ 0, "pcie", 0 },
164653d2a715SThierry Reding 	{ 1, "pcie", 1 },
164753d2a715SThierry Reding 	{ 1, "sata", 0 },
164853d2a715SThierry Reding 	{ 0, NULL,   0 },
164953d2a715SThierry Reding };
165053d2a715SThierry Reding 
165153d2a715SThierry Reding static struct tegra_xusb_lane *
165253d2a715SThierry Reding tegra124_usb3_port_map(struct tegra_xusb_port *port)
165353d2a715SThierry Reding {
165453d2a715SThierry Reding 	return tegra_xusb_port_find_lane(port, tegra124_usb3_map, "usb3-ss");
165553d2a715SThierry Reding }
165653d2a715SThierry Reding 
165753d2a715SThierry Reding static const struct tegra_xusb_port_ops tegra124_usb3_port_ops = {
165853d2a715SThierry Reding 	.enable = tegra124_usb3_port_enable,
165953d2a715SThierry Reding 	.disable = tegra124_usb3_port_disable,
166053d2a715SThierry Reding 	.map = tegra124_usb3_port_map,
166153d2a715SThierry Reding };
166253d2a715SThierry Reding 
166353d2a715SThierry Reding static int
166453d2a715SThierry Reding tegra124_xusb_read_fuse_calibration(struct tegra124_xusb_fuse_calibration *fuse)
166553d2a715SThierry Reding {
166653d2a715SThierry Reding 	unsigned int i;
166753d2a715SThierry Reding 	int err;
166853d2a715SThierry Reding 	u32 value;
166953d2a715SThierry Reding 
167053d2a715SThierry Reding 	err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
167153d2a715SThierry Reding 	if (err < 0)
167253d2a715SThierry Reding 		return err;
167353d2a715SThierry Reding 
167453d2a715SThierry Reding 	for (i = 0; i < ARRAY_SIZE(fuse->hs_curr_level); i++) {
167553d2a715SThierry Reding 		fuse->hs_curr_level[i] =
167653d2a715SThierry Reding 			(value >> FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(i)) &
167753d2a715SThierry Reding 			FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK;
167853d2a715SThierry Reding 	}
167953d2a715SThierry Reding 	fuse->hs_iref_cap =
168053d2a715SThierry Reding 		(value >> FUSE_SKU_CALIB_HS_IREF_CAP_SHIFT) &
168153d2a715SThierry Reding 		FUSE_SKU_CALIB_HS_IREF_CAP_MASK;
168253d2a715SThierry Reding 	fuse->hs_term_range_adj =
168353d2a715SThierry Reding 		(value >> FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT) &
168453d2a715SThierry Reding 		FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK;
168553d2a715SThierry Reding 	fuse->hs_squelch_level =
168653d2a715SThierry Reding 		(value >> FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_SHIFT) &
168753d2a715SThierry Reding 		FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_MASK;
168853d2a715SThierry Reding 
168953d2a715SThierry Reding 	return 0;
169053d2a715SThierry Reding }
169153d2a715SThierry Reding 
169253d2a715SThierry Reding static struct tegra_xusb_padctl *
169353d2a715SThierry Reding tegra124_xusb_padctl_probe(struct device *dev,
169453d2a715SThierry Reding 			   const struct tegra_xusb_padctl_soc *soc)
169553d2a715SThierry Reding {
169653d2a715SThierry Reding 	struct tegra124_xusb_padctl *padctl;
169753d2a715SThierry Reding 	int err;
169853d2a715SThierry Reding 
169953d2a715SThierry Reding 	padctl = devm_kzalloc(dev, sizeof(*padctl), GFP_KERNEL);
170053d2a715SThierry Reding 	if (!padctl)
170153d2a715SThierry Reding 		return ERR_PTR(-ENOMEM);
170253d2a715SThierry Reding 
170353d2a715SThierry Reding 	padctl->base.dev = dev;
170453d2a715SThierry Reding 	padctl->base.soc = soc;
170553d2a715SThierry Reding 
170653d2a715SThierry Reding 	err = tegra124_xusb_read_fuse_calibration(&padctl->fuse);
170753d2a715SThierry Reding 	if (err < 0)
170853d2a715SThierry Reding 		return ERR_PTR(err);
170953d2a715SThierry Reding 
171053d2a715SThierry Reding 	return &padctl->base;
171153d2a715SThierry Reding }
171253d2a715SThierry Reding 
171353d2a715SThierry Reding static void tegra124_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
171453d2a715SThierry Reding {
171553d2a715SThierry Reding }
171653d2a715SThierry Reding 
171753d2a715SThierry Reding static const struct tegra_xusb_padctl_ops tegra124_xusb_padctl_ops = {
171853d2a715SThierry Reding 	.probe = tegra124_xusb_padctl_probe,
171953d2a715SThierry Reding 	.remove = tegra124_xusb_padctl_remove,
172053d2a715SThierry Reding 	.usb3_save_context = tegra124_usb3_save_context,
172153d2a715SThierry Reding 	.hsic_set_idle = tegra124_hsic_set_idle,
172253d2a715SThierry Reding };
172353d2a715SThierry Reding 
1724aa5452f5SThierry Reding static const char * const tegra124_xusb_padctl_supply_names[] = {
1725aa5452f5SThierry Reding 	"avdd-pll-utmip",
1726aa5452f5SThierry Reding 	"avdd-pll-erefe",
1727aa5452f5SThierry Reding 	"avdd-pex-pll",
1728aa5452f5SThierry Reding 	"hvdd-pex-pll-e",
1729aa5452f5SThierry Reding };
1730aa5452f5SThierry Reding 
173153d2a715SThierry Reding const struct tegra_xusb_padctl_soc tegra124_xusb_padctl_soc = {
173253d2a715SThierry Reding 	.num_pads = ARRAY_SIZE(tegra124_pads),
173353d2a715SThierry Reding 	.pads = tegra124_pads,
173453d2a715SThierry Reding 	.ports = {
173553d2a715SThierry Reding 		.usb2 = {
173653d2a715SThierry Reding 			.ops = &tegra124_usb2_port_ops,
173753d2a715SThierry Reding 			.count = 3,
173853d2a715SThierry Reding 		},
173953d2a715SThierry Reding 		.ulpi = {
174053d2a715SThierry Reding 			.ops = &tegra124_ulpi_port_ops,
174153d2a715SThierry Reding 			.count = 1,
174253d2a715SThierry Reding 		},
174353d2a715SThierry Reding 		.hsic = {
174453d2a715SThierry Reding 			.ops = &tegra124_hsic_port_ops,
174553d2a715SThierry Reding 			.count = 2,
174653d2a715SThierry Reding 		},
174753d2a715SThierry Reding 		.usb3 = {
174853d2a715SThierry Reding 			.ops = &tegra124_usb3_port_ops,
174953d2a715SThierry Reding 			.count = 2,
175053d2a715SThierry Reding 		},
175153d2a715SThierry Reding 	},
175253d2a715SThierry Reding 	.ops = &tegra124_xusb_padctl_ops,
1753aa5452f5SThierry Reding 	.supply_names = tegra124_xusb_padctl_supply_names,
1754aa5452f5SThierry Reding 	.num_supplies = ARRAY_SIZE(tegra124_xusb_padctl_supply_names),
175553d2a715SThierry Reding };
175653d2a715SThierry Reding EXPORT_SYMBOL_GPL(tegra124_xusb_padctl_soc);
175753d2a715SThierry Reding 
175853d2a715SThierry Reding MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
175953d2a715SThierry Reding MODULE_DESCRIPTION("NVIDIA Tegra 124 XUSB Pad Controller driver");
176053d2a715SThierry Reding MODULE_LICENSE("GPL v2");
1761