12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 287d66f28SThierry Reding /* 323d5ec3fSJC Kuo * Copyright (c) 2014-2020, NVIDIA CORPORATION. All rights reserved. 487d66f28SThierry Reding * Copyright (C) 2015 Google, Inc. 587d66f28SThierry Reding */ 687d66f28SThierry Reding 787d66f28SThierry Reding #include <linux/clk.h> 887d66f28SThierry Reding #include <linux/clk/tegra.h> 987d66f28SThierry Reding #include <linux/delay.h> 1087d66f28SThierry Reding #include <linux/io.h> 1187d66f28SThierry Reding #include <linux/mailbox_client.h> 1287d66f28SThierry Reding #include <linux/module.h> 1387d66f28SThierry Reding #include <linux/of.h> 14*2d102148SJC Kuo #include <linux/of_platform.h> 1587d66f28SThierry Reding #include <linux/phy/phy.h> 1687d66f28SThierry Reding #include <linux/platform_device.h> 17*2d102148SJC Kuo #include <linux/regmap.h> 1887d66f28SThierry Reding #include <linux/regulator/consumer.h> 1987d66f28SThierry Reding #include <linux/reset.h> 2087d66f28SThierry Reding #include <linux/slab.h> 2187d66f28SThierry Reding 2287d66f28SThierry Reding #include <soc/tegra/fuse.h> 2387d66f28SThierry Reding 2487d66f28SThierry Reding #include "xusb.h" 2587d66f28SThierry Reding 2687d66f28SThierry Reding #define FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(x) \ 2787d66f28SThierry Reding ((x) ? (11 + ((x) - 1) * 6) : 0) 2887d66f28SThierry Reding #define FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK 0x3f 2987d66f28SThierry Reding #define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT 7 3087d66f28SThierry Reding #define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK 0xf 3187d66f28SThierry Reding 3287d66f28SThierry Reding #define FUSE_USB_CALIB_EXT_RPD_CTRL_SHIFT 0 3387d66f28SThierry Reding #define FUSE_USB_CALIB_EXT_RPD_CTRL_MASK 0x1f 3487d66f28SThierry Reding 3587d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX 0x004 3687d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT 16 3787d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_MASK 0x3 3887d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_XUSB 0x1 3987d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT 18 4087d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK 0x3 4187d66f28SThierry Reding #define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB 0x1 4287d66f28SThierry Reding 4387d66f28SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP 0x008 44ac25b6e9SNagarjuna Kristam #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DISABLED(x) (0x0 << ((x) * 4)) 4587d66f28SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(x) (0x1 << ((x) * 4)) 46ac25b6e9SNagarjuna Kristam #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DEVICE(x) (0x2 << ((x) * 4)) 47ac25b6e9SNagarjuna Kristam #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_OTG(x) (0x3 << ((x) * 4)) 4887d66f28SThierry Reding #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(x) (0x3 << ((x) * 4)) 4987d66f28SThierry Reding 5087d66f28SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP 0x014 5187d66f28SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(x) (1 << (((x) * 5) + 4)) 5287d66f28SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_SHIFT(x) ((x) * 5) 5387d66f28SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(x) (0x7 << ((x) * 5)) 5487d66f28SThierry Reding #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(x, v) (((v) & 0x7) << ((x) * 5)) 55a5be28c3SNagarjuna Kristam #define XUSB_PADCTL_SS_PORT_MAP_PORT_DISABLED 0x7 5687d66f28SThierry Reding 57*2d102148SJC Kuo #define XUSB_PADCTL_ELPG_PROGRAM_0 0x20 58*2d102148SJC Kuo #define USB2_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x)) 59*2d102148SJC Kuo #define USB2_PORT_WAKEUP_EVENT(x) BIT((x) + 7) 60*2d102148SJC Kuo #define SS_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 14) 61*2d102148SJC Kuo #define SS_PORT_WAKEUP_EVENT(x) BIT((x) + 21) 62*2d102148SJC Kuo #define USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 28) 63*2d102148SJC Kuo #define USB2_HSIC_PORT_WAKEUP_EVENT(x) BIT((x) + 30) 64*2d102148SJC Kuo #define ALL_WAKE_EVENTS ( \ 65*2d102148SJC Kuo USB2_PORT_WAKEUP_EVENT(0) | USB2_PORT_WAKEUP_EVENT(1) | \ 66*2d102148SJC Kuo USB2_PORT_WAKEUP_EVENT(2) | USB2_PORT_WAKEUP_EVENT(3) | \ 67*2d102148SJC Kuo SS_PORT_WAKEUP_EVENT(0) | SS_PORT_WAKEUP_EVENT(1) | \ 68*2d102148SJC Kuo SS_PORT_WAKEUP_EVENT(2) | SS_PORT_WAKEUP_EVENT(3) | \ 69*2d102148SJC Kuo USB2_HSIC_PORT_WAKEUP_EVENT(0)) 70*2d102148SJC Kuo 7187d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1 0x024 7287d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN (1 << 31) 7387d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 30) 7487d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN (1 << 29) 7587d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(x) (1 << (2 + (x) * 3)) 7687d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(x) \ 7787d66f28SThierry Reding (1 << (1 + (x) * 3)) 7887d66f28SThierry Reding #define XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(x) (1 << ((x) * 3)) 7987d66f28SThierry Reding 8087d66f28SThierry Reding #define XUSB_PADCTL_USB3_PAD_MUX 0x028 8187d66f28SThierry Reding #define XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(x) (1 << (1 + (x))) 8287d66f28SThierry Reding #define XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(x) (1 << (8 + (x))) 8387d66f28SThierry Reding 8490767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL0(x) (0x080 + (x) * 0x40) 8590767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIP (1 << 18) 8690767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIN (1 << 22) 8790767cdfSNagarjuna Kristam 8887d66f28SThierry Reding #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(x) (0x084 + (x) * 0x40) 8987d66f28SThierry Reding #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT 7 9087d66f28SThierry Reding #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_MASK 0x3 91ac25b6e9SNagarjuna Kristam #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_VAL 0x1 9287d66f28SThierry Reding #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18 (1 << 6) 9387d66f28SThierry Reding 9487d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x088 + (x) * 0x40) 9587d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI (1 << 29) 9687d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 (1 << 27) 9787d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD (1 << 26) 9887d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT 0 9987d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK 0x3f 10087d66f28SThierry Reding 10187d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x) (0x08c + (x) * 0x40) 10287d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT 26 10387d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_MASK 0x1f 10487d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT 3 10587d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK 0xf 10687d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2) 10787d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD (1 << 1) 10887d66f28SThierry Reding #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD (1 << 0) 109*2d102148SJC Kuo #define RPD_CTRL(x) (((x) & 0x1f) << 26) 110*2d102148SJC Kuo #define RPD_CTRL_VALUE(x) (((x) >> 26) & 0x1f) 11187d66f28SThierry Reding 11287d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x284 11387d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 11) 11487d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT 3 11587d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK 0x7 11687d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL 0x7 11787d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT 0 11887d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK 0x7 11987d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_VAL 0x2 12087d66f28SThierry Reding 12187d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1 0x288 12287d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_PD_TRK (1 << 26) 12387d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT 19 12487d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_MASK 0x7f 12587d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_VAL 0x0a 12687d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT 12 12787d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK 0x7f 12887d66f28SThierry Reding #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL 0x1e 129*2d102148SJC Kuo #define TCTRL_VALUE(x) (((x) & 0x3f) >> 0) 130*2d102148SJC Kuo #define PCTRL_VALUE(x) (((x) >> 6) & 0x3f) 13187d66f28SThierry Reding 13287d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x300 + (x) * 0x20) 13387d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE (1 << 18) 13487d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 (1 << 17) 13587d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 (1 << 16) 13687d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE (1 << 15) 13787d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 (1 << 14) 13887d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 (1 << 13) 13987d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE (1 << 9) 14087d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 (1 << 8) 14187d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 (1 << 7) 14287d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE (1 << 6) 14387d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 (1 << 5) 14487d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 (1 << 4) 14587d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE (1 << 3) 14687d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 (1 << 2) 14787d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 (1 << 1) 14887d66f28SThierry Reding 14987d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PADX_CTL1(x) (0x304 + (x) * 0x20) 15087d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT 0 15187d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_MASK 0xf 15287d66f28SThierry Reding 15387d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PADX_CTL2(x) (0x308 + (x) * 0x20) 15487d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT 8 15587d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK 0xf 15687d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT 0 15787d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK 0xff 15887d66f28SThierry Reding 15987d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL 0x340 16087d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_PD_TRK (1 << 19) 16187d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT 12 16287d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_MASK 0x7f 16387d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_VAL 0x0a 16487d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT 5 16587d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_MASK 0x7f 16687d66f28SThierry Reding #define XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_VAL 0x1e 16787d66f28SThierry Reding 16887d66f28SThierry Reding #define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL 0x344 16987d66f28SThierry Reding 17087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_P0_CTL1 0x360 17187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT 20 17287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_MASK 0xff 17387d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_USB_VAL 0x19 17487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SATA_VAL 0x1e 17587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_SHIFT 16 17687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK 0x3 17787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_LOCKDET_STATUS (1 << 15) 17887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD (1 << 4) 17987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_ENABLE (1 << 3) 18087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_SHIFT 1 18187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_MASK 0x3 18287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL1_IDDQ (1 << 0) 18387d66f28SThierry Reding 18487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_P0_CTL2 0x364 18587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT 4 18687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK 0xffffff 18787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_VAL 0x136 18887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD (1 << 2) 18987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE (1 << 1) 19087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN (1 << 0) 19187d66f28SThierry Reding 19287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_P0_CTL4 0x36c 193e7f4da4cSThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_XDIGCLK_EN (1 << 19) 19487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN (1 << 15) 19587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT 12 19687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK 0x3 19787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_USB_VAL 0x2 19887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SATA_VAL 0x0 19987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_REFCLKBUF_EN (1 << 8) 20087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_SHIFT 4 20187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_MASK 0xf 20287d66f28SThierry Reding 20387d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_P0_CTL5 0x370 20487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT 16 20587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_MASK 0xff 20687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_VAL 0x2a 20787d66f28SThierry Reding 20887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_P0_CTL8 0x37c 20987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE (1 << 31) 21087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD (1 << 15) 21187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN (1 << 13) 21287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN (1 << 12) 21387d66f28SThierry Reding 21487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL1(x) (0x460 + (x) * 0x40) 21587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT 20 21687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_MASK 0x3 21787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_VAL 0x1 21887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN BIT(18) 21987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD BIT(13) 22087d66f28SThierry Reding 221c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(x) (0x464 + (x) * 0x40) 222c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ BIT(0) 223c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD BIT(1) 224c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK GENMASK(5, 4) 225c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL GENMASK(5, 4) 226c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD BIT(24) 227c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ BIT(8) 228c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD BIT(9) 229c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK GENMASK(13, 12) 230c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL GENMASK(13, 12) 231c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD BIT(25) 232c339605cSJC Kuo 23387d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_S0_CTL1 0x860 23487d66f28SThierry Reding 23587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_S0_CTL2 0x864 23687d66f28SThierry Reding 23787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_S0_CTL4 0x86c 23887d66f28SThierry Reding 23987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_S0_CTL5 0x870 24087d66f28SThierry Reding 24187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_PLL_S0_CTL8 0x87c 24287d66f28SThierry Reding 24387d66f28SThierry Reding #define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1 0x960 244c339605cSJC Kuo #define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2 0x964 24587d66f28SThierry Reding 24687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(x) (0xa60 + (x) * 0x40) 24787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT 16 24887d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_MASK 0x3 24987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_VAL 0x2 25087d66f28SThierry Reding 25187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(x) (0xa64 + (x) * 0x40) 25287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT 0 25387d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_MASK 0xffff 25487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_VAL 0x00fc 25587d66f28SThierry Reding 25687d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL3(x) (0xa68 + (x) * 0x40) 25787d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL3_RX_DFE_VAL 0xc0077f1f 25887d66f28SThierry Reding 25987d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(x) (0xa6c + (x) * 0x40) 26087d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT 16 26187d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_MASK 0xffff 26287d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_VAL 0x01c7 26387d66f28SThierry Reding 26487d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PADX_ECTL6(x) (0xa74 + (x) * 0x40) 26587d66f28SThierry Reding #define XUSB_PADCTL_UPHY_USB3_PAD_ECTL6_RX_EQ_CTRL_H_VAL 0xfcf01368 26687d66f28SThierry Reding 26790767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID 0xc60 26890767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON (1 << 14) 26990767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT 18 27090767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK 0xf 27190767cdfSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING 8 272de792a6dSNagarjuna Kristam #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED 0 27390767cdfSNagarjuna Kristam 274*2d102148SJC Kuo /* USB2 SLEEPWALK registers */ 275*2d102148SJC Kuo #define UTMIP(_port, _offset1, _offset2) \ 276*2d102148SJC Kuo (((_port) <= 2) ? (_offset1) : (_offset2)) 277*2d102148SJC Kuo 278*2d102148SJC Kuo #define PMC_UTMIP_UHSIC_SLEEP_CFG(x) UTMIP(x, 0x1fc, 0x4d0) 279*2d102148SJC Kuo #define UTMIP_MASTER_ENABLE(x) UTMIP(x, BIT(8 * (x)), BIT(0)) 280*2d102148SJC Kuo #define UTMIP_FSLS_USE_PMC(x) UTMIP(x, BIT(8 * (x) + 1), \ 281*2d102148SJC Kuo BIT(1)) 282*2d102148SJC Kuo #define UTMIP_PCTRL_USE_PMC(x) UTMIP(x, BIT(8 * (x) + 2), \ 283*2d102148SJC Kuo BIT(2)) 284*2d102148SJC Kuo #define UTMIP_TCTRL_USE_PMC(x) UTMIP(x, BIT(8 * (x) + 3), \ 285*2d102148SJC Kuo BIT(3)) 286*2d102148SJC Kuo #define UTMIP_WAKE_VAL(_port, _value) (((_value) & 0xf) << \ 287*2d102148SJC Kuo (UTMIP(_port, 8 * (_port) + 4, 4))) 288*2d102148SJC Kuo #define UTMIP_WAKE_VAL_NONE(_port) UTMIP_WAKE_VAL(_port, 12) 289*2d102148SJC Kuo #define UTMIP_WAKE_VAL_ANY(_port) UTMIP_WAKE_VAL(_port, 15) 290*2d102148SJC Kuo 291*2d102148SJC Kuo #define PMC_UTMIP_UHSIC_SLEEP_CFG1 (0x4d0) 292*2d102148SJC Kuo #define UTMIP_RPU_SWITC_LOW_USE_PMC_PX(x) BIT((x) + 8) 293*2d102148SJC Kuo #define UTMIP_RPD_CTRL_USE_PMC_PX(x) BIT((x) + 16) 294*2d102148SJC Kuo 295*2d102148SJC Kuo #define PMC_UTMIP_MASTER_CONFIG (0x274) 296*2d102148SJC Kuo #define UTMIP_PWR(x) UTMIP(x, BIT(x), BIT(4)) 297*2d102148SJC Kuo #define UHSIC_PWR BIT(3) 298*2d102148SJC Kuo 299*2d102148SJC Kuo #define PMC_USB_DEBOUNCE_DEL (0xec) 300*2d102148SJC Kuo #define DEBOUNCE_VAL(x) (((x) & 0xffff) << 0) 301*2d102148SJC Kuo #define UTMIP_LINE_DEB_CNT(x) (((x) & 0xf) << 16) 302*2d102148SJC Kuo #define UHSIC_LINE_DEB_CNT(x) (((x) & 0xf) << 20) 303*2d102148SJC Kuo 304*2d102148SJC Kuo #define PMC_UTMIP_UHSIC_FAKE(x) UTMIP(x, 0x218, 0x294) 305*2d102148SJC Kuo #define UTMIP_FAKE_USBOP_VAL(x) UTMIP(x, BIT(4 * (x)), BIT(8)) 306*2d102148SJC Kuo #define UTMIP_FAKE_USBON_VAL(x) UTMIP(x, BIT(4 * (x) + 1), \ 307*2d102148SJC Kuo BIT(9)) 308*2d102148SJC Kuo #define UTMIP_FAKE_USBOP_EN(x) UTMIP(x, BIT(4 * (x) + 2), \ 309*2d102148SJC Kuo BIT(10)) 310*2d102148SJC Kuo #define UTMIP_FAKE_USBON_EN(x) UTMIP(x, BIT(4 * (x) + 3), \ 311*2d102148SJC Kuo BIT(11)) 312*2d102148SJC Kuo 313*2d102148SJC Kuo #define PMC_UTMIP_UHSIC_SLEEPWALK_CFG(x) UTMIP(x, 0x200, 0x288) 314*2d102148SJC Kuo #define UTMIP_LINEVAL_WALK_EN(x) UTMIP(x, BIT(8 * (x) + 7), \ 315*2d102148SJC Kuo BIT(15)) 316*2d102148SJC Kuo 317*2d102148SJC Kuo #define PMC_USB_AO (0xf0) 318*2d102148SJC Kuo #define USBOP_VAL_PD(x) UTMIP(x, BIT(4 * (x)), BIT(20)) 319*2d102148SJC Kuo #define USBON_VAL_PD(x) UTMIP(x, BIT(4 * (x) + 1), \ 320*2d102148SJC Kuo BIT(21)) 321*2d102148SJC Kuo #define STROBE_VAL_PD BIT(12) 322*2d102148SJC Kuo #define DATA0_VAL_PD BIT(13) 323*2d102148SJC Kuo #define DATA1_VAL_PD BIT(24) 324*2d102148SJC Kuo 325*2d102148SJC Kuo #define PMC_UTMIP_UHSIC_SAVED_STATE(x) UTMIP(x, 0x1f0, 0x280) 326*2d102148SJC Kuo #define SPEED(_port, _value) (((_value) & 0x3) << \ 327*2d102148SJC Kuo (UTMIP(_port, 8 * (_port), 8))) 328*2d102148SJC Kuo #define UTMI_HS(_port) SPEED(_port, 0) 329*2d102148SJC Kuo #define UTMI_FS(_port) SPEED(_port, 1) 330*2d102148SJC Kuo #define UTMI_LS(_port) SPEED(_port, 2) 331*2d102148SJC Kuo #define UTMI_RST(_port) SPEED(_port, 3) 332*2d102148SJC Kuo 333*2d102148SJC Kuo #define PMC_UTMIP_UHSIC_TRIGGERS (0x1ec) 334*2d102148SJC Kuo #define UTMIP_CLR_WALK_PTR(x) UTMIP(x, BIT(x), BIT(16)) 335*2d102148SJC Kuo #define UTMIP_CAP_CFG(x) UTMIP(x, BIT((x) + 4), BIT(17)) 336*2d102148SJC Kuo #define UTMIP_CLR_WAKE_ALARM(x) UTMIP(x, BIT((x) + 12), \ 337*2d102148SJC Kuo BIT(19)) 338*2d102148SJC Kuo #define UHSIC_CLR_WALK_PTR BIT(3) 339*2d102148SJC Kuo #define UHSIC_CLR_WAKE_ALARM BIT(15) 340*2d102148SJC Kuo 341*2d102148SJC Kuo #define PMC_UTMIP_SLEEPWALK_PX(x) UTMIP(x, 0x204 + (4 * (x)), \ 342*2d102148SJC Kuo 0x4e0) 343*2d102148SJC Kuo /* phase A */ 344*2d102148SJC Kuo #define UTMIP_USBOP_RPD_A BIT(0) 345*2d102148SJC Kuo #define UTMIP_USBON_RPD_A BIT(1) 346*2d102148SJC Kuo #define UTMIP_AP_A BIT(4) 347*2d102148SJC Kuo #define UTMIP_AN_A BIT(5) 348*2d102148SJC Kuo #define UTMIP_HIGHZ_A BIT(6) 349*2d102148SJC Kuo /* phase B */ 350*2d102148SJC Kuo #define UTMIP_USBOP_RPD_B BIT(8) 351*2d102148SJC Kuo #define UTMIP_USBON_RPD_B BIT(9) 352*2d102148SJC Kuo #define UTMIP_AP_B BIT(12) 353*2d102148SJC Kuo #define UTMIP_AN_B BIT(13) 354*2d102148SJC Kuo #define UTMIP_HIGHZ_B BIT(14) 355*2d102148SJC Kuo /* phase C */ 356*2d102148SJC Kuo #define UTMIP_USBOP_RPD_C BIT(16) 357*2d102148SJC Kuo #define UTMIP_USBON_RPD_C BIT(17) 358*2d102148SJC Kuo #define UTMIP_AP_C BIT(20) 359*2d102148SJC Kuo #define UTMIP_AN_C BIT(21) 360*2d102148SJC Kuo #define UTMIP_HIGHZ_C BIT(22) 361*2d102148SJC Kuo /* phase D */ 362*2d102148SJC Kuo #define UTMIP_USBOP_RPD_D BIT(24) 363*2d102148SJC Kuo #define UTMIP_USBON_RPD_D BIT(25) 364*2d102148SJC Kuo #define UTMIP_AP_D BIT(28) 365*2d102148SJC Kuo #define UTMIP_AN_D BIT(29) 366*2d102148SJC Kuo #define UTMIP_HIGHZ_D BIT(30) 367*2d102148SJC Kuo 368*2d102148SJC Kuo #define PMC_UTMIP_UHSIC_LINE_WAKEUP (0x26c) 369*2d102148SJC Kuo #define UTMIP_LINE_WAKEUP_EN(x) UTMIP(x, BIT(x), BIT(4)) 370*2d102148SJC Kuo #define UHSIC_LINE_WAKEUP_EN BIT(3) 371*2d102148SJC Kuo 372*2d102148SJC Kuo #define PMC_UTMIP_TERM_PAD_CFG (0x1f8) 373*2d102148SJC Kuo #define PCTRL_VAL(x) (((x) & 0x3f) << 1) 374*2d102148SJC Kuo #define TCTRL_VAL(x) (((x) & 0x3f) << 7) 375*2d102148SJC Kuo 376*2d102148SJC Kuo #define PMC_UTMIP_PAD_CFGX(x) (0x4c0 + (4 * (x))) 377*2d102148SJC Kuo #define RPD_CTRL_PX(x) (((x) & 0x1f) << 22) 378*2d102148SJC Kuo 379*2d102148SJC Kuo #define PMC_UHSIC_SLEEP_CFG PMC_UTMIP_UHSIC_SLEEP_CFG(0) 380*2d102148SJC Kuo #define UHSIC_MASTER_ENABLE BIT(24) 381*2d102148SJC Kuo #define UHSIC_WAKE_VAL(_value) (((_value) & 0xf) << 28) 382*2d102148SJC Kuo #define UHSIC_WAKE_VAL_SD10 UHSIC_WAKE_VAL(2) 383*2d102148SJC Kuo #define UHSIC_WAKE_VAL_NONE UHSIC_WAKE_VAL(12) 384*2d102148SJC Kuo 385*2d102148SJC Kuo #define PMC_UHSIC_FAKE PMC_UTMIP_UHSIC_FAKE(0) 386*2d102148SJC Kuo #define UHSIC_FAKE_STROBE_VAL BIT(12) 387*2d102148SJC Kuo #define UHSIC_FAKE_DATA_VAL BIT(13) 388*2d102148SJC Kuo #define UHSIC_FAKE_STROBE_EN BIT(14) 389*2d102148SJC Kuo #define UHSIC_FAKE_DATA_EN BIT(15) 390*2d102148SJC Kuo 391*2d102148SJC Kuo #define PMC_UHSIC_SAVED_STATE PMC_UTMIP_UHSIC_SAVED_STATE(0) 392*2d102148SJC Kuo #define UHSIC_MODE(_value) (((_value) & 0x1) << 24) 393*2d102148SJC Kuo #define UHSIC_HS UHSIC_MODE(0) 394*2d102148SJC Kuo #define UHSIC_RST UHSIC_MODE(1) 395*2d102148SJC Kuo 396*2d102148SJC Kuo #define PMC_UHSIC_SLEEPWALK_CFG PMC_UTMIP_UHSIC_SLEEPWALK_CFG(0) 397*2d102148SJC Kuo #define UHSIC_WAKE_WALK_EN BIT(30) 398*2d102148SJC Kuo #define UHSIC_LINEVAL_WALK_EN BIT(31) 399*2d102148SJC Kuo 400*2d102148SJC Kuo #define PMC_UHSIC_SLEEPWALK_P0 (0x210) 401*2d102148SJC Kuo #define UHSIC_DATA0_RPD_A BIT(1) 402*2d102148SJC Kuo #define UHSIC_DATA0_RPU_B BIT(11) 403*2d102148SJC Kuo #define UHSIC_DATA0_RPU_C BIT(19) 404*2d102148SJC Kuo #define UHSIC_DATA0_RPU_D BIT(27) 405*2d102148SJC Kuo #define UHSIC_STROBE_RPU_A BIT(2) 406*2d102148SJC Kuo #define UHSIC_STROBE_RPD_B BIT(8) 407*2d102148SJC Kuo #define UHSIC_STROBE_RPD_C BIT(16) 408*2d102148SJC Kuo #define UHSIC_STROBE_RPD_D BIT(24) 409*2d102148SJC Kuo 41087d66f28SThierry Reding struct tegra210_xusb_fuse_calibration { 41187d66f28SThierry Reding u32 hs_curr_level[4]; 41287d66f28SThierry Reding u32 hs_term_range_adj; 41387d66f28SThierry Reding u32 rpd_ctrl; 41487d66f28SThierry Reding }; 41587d66f28SThierry Reding 416*2d102148SJC Kuo struct tegra210_xusb_padctl_context { 417*2d102148SJC Kuo u32 usb2_pad_mux; 418*2d102148SJC Kuo u32 usb2_port_cap; 419*2d102148SJC Kuo u32 ss_port_map; 420*2d102148SJC Kuo u32 usb3_pad_mux; 421*2d102148SJC Kuo }; 422*2d102148SJC Kuo 42387d66f28SThierry Reding struct tegra210_xusb_padctl { 42487d66f28SThierry Reding struct tegra_xusb_padctl base; 425*2d102148SJC Kuo struct regmap *regmap; 42687d66f28SThierry Reding 42787d66f28SThierry Reding struct tegra210_xusb_fuse_calibration fuse; 428*2d102148SJC Kuo struct tegra210_xusb_padctl_context context; 42987d66f28SThierry Reding }; 43087d66f28SThierry Reding 43187d66f28SThierry Reding static inline struct tegra210_xusb_padctl * 43287d66f28SThierry Reding to_tegra210_xusb_padctl(struct tegra_xusb_padctl *padctl) 43387d66f28SThierry Reding { 43487d66f28SThierry Reding return container_of(padctl, struct tegra210_xusb_padctl, base); 43587d66f28SThierry Reding } 43687d66f28SThierry Reding 43723d5ec3fSJC Kuo static const struct tegra_xusb_lane_map tegra210_usb3_map[] = { 43823d5ec3fSJC Kuo { 0, "pcie", 6 }, 43923d5ec3fSJC Kuo { 1, "pcie", 5 }, 44023d5ec3fSJC Kuo { 2, "pcie", 0 }, 44123d5ec3fSJC Kuo { 2, "pcie", 3 }, 44223d5ec3fSJC Kuo { 3, "pcie", 4 }, 44323d5ec3fSJC Kuo { 3, "sata", 0 }, 44423d5ec3fSJC Kuo { 0, NULL, 0 } 44523d5ec3fSJC Kuo }; 44623d5ec3fSJC Kuo 44723d5ec3fSJC Kuo static int tegra210_usb3_lane_map(struct tegra_xusb_lane *lane) 44823d5ec3fSJC Kuo { 44923d5ec3fSJC Kuo const struct tegra_xusb_lane_map *map; 45023d5ec3fSJC Kuo 45123d5ec3fSJC Kuo for (map = tegra210_usb3_map; map->type; map++) { 45223d5ec3fSJC Kuo if (map->index == lane->index && 45323d5ec3fSJC Kuo strcmp(map->type, lane->pad->soc->name) == 0) { 45423d5ec3fSJC Kuo dev_dbg(lane->pad->padctl->dev, "lane = %s map to port = usb3-%d\n", 45523d5ec3fSJC Kuo lane->pad->soc->lanes[lane->index].name, map->port); 45623d5ec3fSJC Kuo return map->port; 45723d5ec3fSJC Kuo } 45823d5ec3fSJC Kuo } 45923d5ec3fSJC Kuo 46023d5ec3fSJC Kuo return -EINVAL; 46123d5ec3fSJC Kuo } 46223d5ec3fSJC Kuo 46387d66f28SThierry Reding /* must be called under padctl->lock */ 46487d66f28SThierry Reding static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl) 46587d66f28SThierry Reding { 46687d66f28SThierry Reding struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(padctl->pcie); 46787d66f28SThierry Reding unsigned long timeout; 46887d66f28SThierry Reding u32 value; 4692352fdb0SJC Kuo unsigned int i; 47087d66f28SThierry Reding int err; 47187d66f28SThierry Reding 4722352fdb0SJC Kuo if (pcie->enable) 47387d66f28SThierry Reding return 0; 47487d66f28SThierry Reding 47587d66f28SThierry Reding err = clk_prepare_enable(pcie->pll); 47687d66f28SThierry Reding if (err < 0) 47787d66f28SThierry Reding return err; 47887d66f28SThierry Reding 4792352fdb0SJC Kuo if (tegra210_plle_hw_sequence_is_enabled()) 4802352fdb0SJC Kuo goto skip_pll_init; 4812352fdb0SJC Kuo 48287d66f28SThierry Reding err = reset_control_deassert(pcie->rst); 48387d66f28SThierry Reding if (err < 0) 48487d66f28SThierry Reding goto disable; 48587d66f28SThierry Reding 48687d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); 48787d66f28SThierry Reding value &= ~(XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK << 48887d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT); 48987d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_VAL << 49087d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT; 49187d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2); 49287d66f28SThierry Reding 49387d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL5); 49487d66f28SThierry Reding value &= ~(XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_MASK << 49587d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT); 49687d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_VAL << 49787d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT; 49887d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL5); 49987d66f28SThierry Reding 50087d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); 50187d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD; 50287d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1); 50387d66f28SThierry Reding 50487d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); 50587d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD; 50687d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2); 50787d66f28SThierry Reding 50887d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8); 50987d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD; 51087d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8); 51187d66f28SThierry Reding 51287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL4); 51387d66f28SThierry Reding value &= ~((XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK << 51487d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT) | 51587d66f28SThierry Reding (XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_MASK << 51687d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_SHIFT)); 51787d66f28SThierry Reding value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_USB_VAL << 51887d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT) | 51987d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN; 52087d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL4); 52187d66f28SThierry Reding 52287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); 52387d66f28SThierry Reding value &= ~((XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK << 52487d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_SHIFT) | 52587d66f28SThierry Reding (XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_MASK << 52687d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT)); 52787d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_USB_VAL << 52887d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT; 52987d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1); 53087d66f28SThierry Reding 53187d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); 53287d66f28SThierry Reding value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_IDDQ; 53387d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1); 53487d66f28SThierry Reding 53587d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); 53687d66f28SThierry Reding value &= ~(XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_MASK << 53787d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_SHIFT); 53887d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1); 53987d66f28SThierry Reding 54087d66f28SThierry Reding usleep_range(10, 20); 54187d66f28SThierry Reding 54287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL4); 54387d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL4_REFCLKBUF_EN; 54487d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL4); 54587d66f28SThierry Reding 54687d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); 54787d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN; 54887d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2); 54987d66f28SThierry Reding 55087d66f28SThierry Reding timeout = jiffies + msecs_to_jiffies(100); 55187d66f28SThierry Reding 55287d66f28SThierry Reding while (time_before(jiffies, timeout)) { 55387d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); 55487d66f28SThierry Reding if (value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE) 55587d66f28SThierry Reding break; 55687d66f28SThierry Reding 55787d66f28SThierry Reding usleep_range(10, 20); 55887d66f28SThierry Reding } 55987d66f28SThierry Reding 56087d66f28SThierry Reding if (time_after_eq(jiffies, timeout)) { 56187d66f28SThierry Reding err = -ETIMEDOUT; 56287d66f28SThierry Reding goto reset; 56387d66f28SThierry Reding } 56487d66f28SThierry Reding 56587d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); 56687d66f28SThierry Reding value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN; 56787d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2); 56887d66f28SThierry Reding 56987d66f28SThierry Reding timeout = jiffies + msecs_to_jiffies(100); 57087d66f28SThierry Reding 57187d66f28SThierry Reding while (time_before(jiffies, timeout)) { 57287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); 57387d66f28SThierry Reding if (!(value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE)) 57487d66f28SThierry Reding break; 57587d66f28SThierry Reding 57687d66f28SThierry Reding usleep_range(10, 20); 57787d66f28SThierry Reding } 57887d66f28SThierry Reding 57987d66f28SThierry Reding if (time_after_eq(jiffies, timeout)) { 58087d66f28SThierry Reding err = -ETIMEDOUT; 58187d66f28SThierry Reding goto reset; 58287d66f28SThierry Reding } 58387d66f28SThierry Reding 58487d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); 58587d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL1_ENABLE; 58687d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1); 58787d66f28SThierry Reding 58887d66f28SThierry Reding timeout = jiffies + msecs_to_jiffies(100); 58987d66f28SThierry Reding 59087d66f28SThierry Reding while (time_before(jiffies, timeout)) { 59187d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); 59287d66f28SThierry Reding if (value & XUSB_PADCTL_UPHY_PLL_CTL1_LOCKDET_STATUS) 59387d66f28SThierry Reding break; 59487d66f28SThierry Reding 59587d66f28SThierry Reding usleep_range(10, 20); 59687d66f28SThierry Reding } 59787d66f28SThierry Reding 59887d66f28SThierry Reding if (time_after_eq(jiffies, timeout)) { 59987d66f28SThierry Reding err = -ETIMEDOUT; 60087d66f28SThierry Reding goto reset; 60187d66f28SThierry Reding } 60287d66f28SThierry Reding 60387d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8); 60487d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN | 60587d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN; 60687d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8); 60787d66f28SThierry Reding 60887d66f28SThierry Reding timeout = jiffies + msecs_to_jiffies(100); 60987d66f28SThierry Reding 61087d66f28SThierry Reding while (time_before(jiffies, timeout)) { 61187d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8); 61287d66f28SThierry Reding if (value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE) 61387d66f28SThierry Reding break; 61487d66f28SThierry Reding 61587d66f28SThierry Reding usleep_range(10, 20); 61687d66f28SThierry Reding } 61787d66f28SThierry Reding 61887d66f28SThierry Reding if (time_after_eq(jiffies, timeout)) { 61987d66f28SThierry Reding err = -ETIMEDOUT; 62087d66f28SThierry Reding goto reset; 62187d66f28SThierry Reding } 62287d66f28SThierry Reding 62387d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8); 62487d66f28SThierry Reding value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN; 62587d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8); 62687d66f28SThierry Reding 62787d66f28SThierry Reding timeout = jiffies + msecs_to_jiffies(100); 62887d66f28SThierry Reding 62987d66f28SThierry Reding while (time_before(jiffies, timeout)) { 63087d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8); 63187d66f28SThierry Reding if (!(value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE)) 63287d66f28SThierry Reding break; 63387d66f28SThierry Reding 63487d66f28SThierry Reding usleep_range(10, 20); 63587d66f28SThierry Reding } 63687d66f28SThierry Reding 63787d66f28SThierry Reding if (time_after_eq(jiffies, timeout)) { 63887d66f28SThierry Reding err = -ETIMEDOUT; 63987d66f28SThierry Reding goto reset; 64087d66f28SThierry Reding } 64187d66f28SThierry Reding 64287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8); 64387d66f28SThierry Reding value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN; 64487d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8); 64587d66f28SThierry Reding 64687d66f28SThierry Reding tegra210_xusb_pll_hw_control_enable(); 64787d66f28SThierry Reding 64887d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); 64987d66f28SThierry Reding value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD; 65087d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1); 65187d66f28SThierry Reding 65287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); 65387d66f28SThierry Reding value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD; 65487d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2); 65587d66f28SThierry Reding 65687d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8); 65787d66f28SThierry Reding value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD; 65887d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8); 65987d66f28SThierry Reding 66087d66f28SThierry Reding usleep_range(10, 20); 66187d66f28SThierry Reding 66287d66f28SThierry Reding tegra210_xusb_pll_hw_sequence_start(); 66387d66f28SThierry Reding 6642352fdb0SJC Kuo skip_pll_init: 6652352fdb0SJC Kuo pcie->enable = true; 6662352fdb0SJC Kuo 6672352fdb0SJC Kuo for (i = 0; i < padctl->pcie->soc->num_lanes; i++) { 6682352fdb0SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); 6692352fdb0SJC Kuo value |= XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(i); 6702352fdb0SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); 6712352fdb0SJC Kuo } 67287d66f28SThierry Reding 67387d66f28SThierry Reding return 0; 67487d66f28SThierry Reding 67587d66f28SThierry Reding reset: 67687d66f28SThierry Reding reset_control_assert(pcie->rst); 67787d66f28SThierry Reding disable: 67887d66f28SThierry Reding clk_disable_unprepare(pcie->pll); 67987d66f28SThierry Reding return err; 68087d66f28SThierry Reding } 68187d66f28SThierry Reding 68287d66f28SThierry Reding static void tegra210_pex_uphy_disable(struct tegra_xusb_padctl *padctl) 68387d66f28SThierry Reding { 68487d66f28SThierry Reding struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(padctl->pcie); 6852352fdb0SJC Kuo u32 value; 6862352fdb0SJC Kuo unsigned int i; 68787d66f28SThierry Reding 6882352fdb0SJC Kuo if (WARN_ON(!pcie->enable)) 68923d5ec3fSJC Kuo return; 69087d66f28SThierry Reding 6912352fdb0SJC Kuo pcie->enable = false; 69287d66f28SThierry Reding 6932352fdb0SJC Kuo for (i = 0; i < padctl->pcie->soc->num_lanes; i++) { 6942352fdb0SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); 6952352fdb0SJC Kuo value &= ~XUSB_PADCTL_USB3_PAD_MUX_PCIE_IDDQ_DISABLE(i); 6962352fdb0SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); 6972352fdb0SJC Kuo } 6982352fdb0SJC Kuo 69987d66f28SThierry Reding clk_disable_unprepare(pcie->pll); 70087d66f28SThierry Reding } 70187d66f28SThierry Reding 70287d66f28SThierry Reding /* must be called under padctl->lock */ 7032352fdb0SJC Kuo static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl) 70487d66f28SThierry Reding { 70587d66f28SThierry Reding struct tegra_xusb_sata_pad *sata = to_sata_pad(padctl->sata); 7062352fdb0SJC Kuo struct tegra_xusb_lane *lane = tegra_xusb_find_lane(padctl, "sata", 0); 70787d66f28SThierry Reding unsigned long timeout; 70887d66f28SThierry Reding u32 value; 7092352fdb0SJC Kuo unsigned int i; 71087d66f28SThierry Reding int err; 7112352fdb0SJC Kuo bool usb; 71287d66f28SThierry Reding 7132352fdb0SJC Kuo if (sata->enable) 71487d66f28SThierry Reding return 0; 7152352fdb0SJC Kuo 7162352fdb0SJC Kuo if (IS_ERR(lane)) 7172352fdb0SJC Kuo return 0; 7182352fdb0SJC Kuo 7192352fdb0SJC Kuo if (tegra210_plle_hw_sequence_is_enabled()) 7202352fdb0SJC Kuo goto skip_pll_init; 7212352fdb0SJC Kuo 7222352fdb0SJC Kuo usb = tegra_xusb_lane_check(lane, "usb3-ss"); 72387d66f28SThierry Reding 72487d66f28SThierry Reding err = clk_prepare_enable(sata->pll); 72587d66f28SThierry Reding if (err < 0) 72687d66f28SThierry Reding return err; 72787d66f28SThierry Reding 72887d66f28SThierry Reding err = reset_control_deassert(sata->rst); 72987d66f28SThierry Reding if (err < 0) 73087d66f28SThierry Reding goto disable; 73187d66f28SThierry Reding 73287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2); 73387d66f28SThierry Reding value &= ~(XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK << 73487d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT); 73587d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_VAL << 73687d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT; 73787d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2); 73887d66f28SThierry Reding 73987d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL5); 74087d66f28SThierry Reding value &= ~(XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_MASK << 74187d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT); 74287d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_VAL << 74387d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL5_DCO_CTRL_SHIFT; 74487d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL5); 74587d66f28SThierry Reding 74687d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1); 74787d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD; 74887d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1); 74987d66f28SThierry Reding 75087d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2); 75187d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD; 75287d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2); 75387d66f28SThierry Reding 75487d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8); 75587d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD; 75687d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8); 75787d66f28SThierry Reding 75887d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL4); 75987d66f28SThierry Reding value &= ~((XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK << 76087d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT) | 76187d66f28SThierry Reding (XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_MASK << 76287d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL4_REFCLK_SEL_SHIFT)); 76387d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN; 76487d66f28SThierry Reding 76587d66f28SThierry Reding if (usb) 76687d66f28SThierry Reding value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_USB_VAL << 76787d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT); 76887d66f28SThierry Reding else 76987d66f28SThierry Reding value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SATA_VAL << 77087d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT); 77187d66f28SThierry Reding 772e7f4da4cSThierry Reding value &= ~XUSB_PADCTL_UPHY_PLL_CTL4_XDIGCLK_EN; 77387d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL4); 77487d66f28SThierry Reding 77587d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1); 77687d66f28SThierry Reding value &= ~((XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK << 77787d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_SHIFT) | 77887d66f28SThierry Reding (XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_MASK << 77987d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT)); 78087d66f28SThierry Reding 78187d66f28SThierry Reding if (usb) 78287d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_USB_VAL << 78387d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT; 78487d66f28SThierry Reding else 78587d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SATA_VAL << 78687d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_NDIV_SHIFT; 78787d66f28SThierry Reding 78887d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1); 78987d66f28SThierry Reding 79087d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1); 79187d66f28SThierry Reding value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_IDDQ; 79287d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1); 79387d66f28SThierry Reding 79487d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1); 79587d66f28SThierry Reding value &= ~(XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_MASK << 79687d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL1_SLEEP_SHIFT); 79787d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1); 79887d66f28SThierry Reding 79987d66f28SThierry Reding usleep_range(10, 20); 80087d66f28SThierry Reding 80187d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL4); 80287d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL4_REFCLKBUF_EN; 80387d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL4); 80487d66f28SThierry Reding 80587d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2); 80687d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN; 80787d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2); 80887d66f28SThierry Reding 80987d66f28SThierry Reding timeout = jiffies + msecs_to_jiffies(100); 81087d66f28SThierry Reding 81187d66f28SThierry Reding while (time_before(jiffies, timeout)) { 81287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2); 81387d66f28SThierry Reding if (value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE) 81487d66f28SThierry Reding break; 81587d66f28SThierry Reding 81687d66f28SThierry Reding usleep_range(10, 20); 81787d66f28SThierry Reding } 81887d66f28SThierry Reding 81987d66f28SThierry Reding if (time_after_eq(jiffies, timeout)) { 82087d66f28SThierry Reding err = -ETIMEDOUT; 82187d66f28SThierry Reding goto reset; 82287d66f28SThierry Reding } 82387d66f28SThierry Reding 82487d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2); 82587d66f28SThierry Reding value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN; 82687d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2); 82787d66f28SThierry Reding 82887d66f28SThierry Reding timeout = jiffies + msecs_to_jiffies(100); 82987d66f28SThierry Reding 83087d66f28SThierry Reding while (time_before(jiffies, timeout)) { 83187d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2); 83287d66f28SThierry Reding if (!(value & XUSB_PADCTL_UPHY_PLL_CTL2_CAL_DONE)) 83387d66f28SThierry Reding break; 83487d66f28SThierry Reding 83587d66f28SThierry Reding usleep_range(10, 20); 83687d66f28SThierry Reding } 83787d66f28SThierry Reding 83887d66f28SThierry Reding if (time_after_eq(jiffies, timeout)) { 83987d66f28SThierry Reding err = -ETIMEDOUT; 84087d66f28SThierry Reding goto reset; 84187d66f28SThierry Reding } 84287d66f28SThierry Reding 84387d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1); 84487d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL1_ENABLE; 84587d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1); 84687d66f28SThierry Reding 84787d66f28SThierry Reding timeout = jiffies + msecs_to_jiffies(100); 84887d66f28SThierry Reding 84987d66f28SThierry Reding while (time_before(jiffies, timeout)) { 85087d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1); 85187d66f28SThierry Reding if (value & XUSB_PADCTL_UPHY_PLL_CTL1_LOCKDET_STATUS) 85287d66f28SThierry Reding break; 85387d66f28SThierry Reding 85487d66f28SThierry Reding usleep_range(10, 20); 85587d66f28SThierry Reding } 85687d66f28SThierry Reding 85787d66f28SThierry Reding if (time_after_eq(jiffies, timeout)) { 85887d66f28SThierry Reding err = -ETIMEDOUT; 85987d66f28SThierry Reding goto reset; 86087d66f28SThierry Reding } 86187d66f28SThierry Reding 86287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8); 86387d66f28SThierry Reding value |= XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN | 86487d66f28SThierry Reding XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN; 86587d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8); 86687d66f28SThierry Reding 86787d66f28SThierry Reding timeout = jiffies + msecs_to_jiffies(100); 86887d66f28SThierry Reding 86987d66f28SThierry Reding while (time_before(jiffies, timeout)) { 87087d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8); 87187d66f28SThierry Reding if (value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE) 87287d66f28SThierry Reding break; 87387d66f28SThierry Reding 87487d66f28SThierry Reding usleep_range(10, 20); 87587d66f28SThierry Reding } 87687d66f28SThierry Reding 87787d66f28SThierry Reding if (time_after_eq(jiffies, timeout)) { 87887d66f28SThierry Reding err = -ETIMEDOUT; 87987d66f28SThierry Reding goto reset; 88087d66f28SThierry Reding } 88187d66f28SThierry Reding 88287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8); 88387d66f28SThierry Reding value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_EN; 88487d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8); 88587d66f28SThierry Reding 88687d66f28SThierry Reding timeout = jiffies + msecs_to_jiffies(100); 88787d66f28SThierry Reding 88887d66f28SThierry Reding while (time_before(jiffies, timeout)) { 88987d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8); 89087d66f28SThierry Reding if (!(value & XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_DONE)) 89187d66f28SThierry Reding break; 89287d66f28SThierry Reding 89387d66f28SThierry Reding usleep_range(10, 20); 89487d66f28SThierry Reding } 89587d66f28SThierry Reding 89687d66f28SThierry Reding if (time_after_eq(jiffies, timeout)) { 89787d66f28SThierry Reding err = -ETIMEDOUT; 89887d66f28SThierry Reding goto reset; 89987d66f28SThierry Reding } 90087d66f28SThierry Reding 90187d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8); 90287d66f28SThierry Reding value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN; 90387d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8); 90487d66f28SThierry Reding 90587d66f28SThierry Reding tegra210_sata_pll_hw_control_enable(); 90687d66f28SThierry Reding 90787d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1); 90887d66f28SThierry Reding value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD; 90987d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL1); 91087d66f28SThierry Reding 91187d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL2); 91287d66f28SThierry Reding value &= ~XUSB_PADCTL_UPHY_PLL_CTL2_CAL_OVRD; 91387d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL2); 91487d66f28SThierry Reding 91587d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL8); 91687d66f28SThierry Reding value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_OVRD; 91787d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL8); 91887d66f28SThierry Reding 91987d66f28SThierry Reding usleep_range(10, 20); 92087d66f28SThierry Reding 92187d66f28SThierry Reding tegra210_sata_pll_hw_sequence_start(); 92287d66f28SThierry Reding 9232352fdb0SJC Kuo skip_pll_init: 9242352fdb0SJC Kuo sata->enable = true; 9252352fdb0SJC Kuo 9262352fdb0SJC Kuo for (i = 0; i < padctl->sata->soc->num_lanes; i++) { 9272352fdb0SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); 9282352fdb0SJC Kuo value |= XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(i); 9292352fdb0SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); 9302352fdb0SJC Kuo } 93187d66f28SThierry Reding 93287d66f28SThierry Reding return 0; 93387d66f28SThierry Reding 93487d66f28SThierry Reding reset: 93587d66f28SThierry Reding reset_control_assert(sata->rst); 93687d66f28SThierry Reding disable: 93787d66f28SThierry Reding clk_disable_unprepare(sata->pll); 93887d66f28SThierry Reding return err; 93987d66f28SThierry Reding } 94087d66f28SThierry Reding 94187d66f28SThierry Reding static void tegra210_sata_uphy_disable(struct tegra_xusb_padctl *padctl) 94287d66f28SThierry Reding { 94387d66f28SThierry Reding struct tegra_xusb_sata_pad *sata = to_sata_pad(padctl->sata); 9442352fdb0SJC Kuo u32 value; 9452352fdb0SJC Kuo unsigned int i; 94687d66f28SThierry Reding 9472352fdb0SJC Kuo if (WARN_ON(!sata->enable)) 94823d5ec3fSJC Kuo return; 94987d66f28SThierry Reding 9502352fdb0SJC Kuo sata->enable = false; 95187d66f28SThierry Reding 9522352fdb0SJC Kuo for (i = 0; i < padctl->sata->soc->num_lanes; i++) { 9532352fdb0SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); 9542352fdb0SJC Kuo value &= ~XUSB_PADCTL_USB3_PAD_MUX_SATA_IDDQ_DISABLE(i); 9552352fdb0SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); 9562352fdb0SJC Kuo } 9572352fdb0SJC Kuo 95887d66f28SThierry Reding clk_disable_unprepare(sata->pll); 95987d66f28SThierry Reding } 96087d66f28SThierry Reding 9612352fdb0SJC Kuo static void tegra210_aux_mux_lp0_clamp_disable(struct tegra_xusb_padctl *padctl) 96287d66f28SThierry Reding { 96387d66f28SThierry Reding u32 value; 96487d66f28SThierry Reding 96587d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 96687d66f28SThierry Reding value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN; 96787d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 96887d66f28SThierry Reding 96987d66f28SThierry Reding usleep_range(100, 200); 97087d66f28SThierry Reding 97187d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 97287d66f28SThierry Reding value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY; 97387d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 97487d66f28SThierry Reding 97587d66f28SThierry Reding usleep_range(100, 200); 97687d66f28SThierry Reding 97787d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 97887d66f28SThierry Reding value &= ~XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN; 97987d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 98087d66f28SThierry Reding } 98187d66f28SThierry Reding 9822352fdb0SJC Kuo static void tegra210_aux_mux_lp0_clamp_enable(struct tegra_xusb_padctl *padctl) 98387d66f28SThierry Reding { 98487d66f28SThierry Reding u32 value; 98587d66f28SThierry Reding 98687d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 98787d66f28SThierry Reding value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN; 98887d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 98987d66f28SThierry Reding 99087d66f28SThierry Reding usleep_range(100, 200); 99187d66f28SThierry Reding 99287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 99387d66f28SThierry Reding value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY; 99487d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 99587d66f28SThierry Reding 99687d66f28SThierry Reding usleep_range(100, 200); 99787d66f28SThierry Reding 99887d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 99987d66f28SThierry Reding value |= XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN; 100087d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 10012352fdb0SJC Kuo } 100287d66f28SThierry Reding 10032352fdb0SJC Kuo static int tegra210_uphy_init(struct tegra_xusb_padctl *padctl) 10042352fdb0SJC Kuo { 10052352fdb0SJC Kuo if (padctl->pcie) 10062352fdb0SJC Kuo tegra210_pex_uphy_enable(padctl); 10072352fdb0SJC Kuo 10082352fdb0SJC Kuo if (padctl->sata) 10092352fdb0SJC Kuo tegra210_sata_uphy_enable(padctl); 10102352fdb0SJC Kuo 10112352fdb0SJC Kuo if (!tegra210_plle_hw_sequence_is_enabled()) 10122352fdb0SJC Kuo tegra210_plle_hw_sequence_start(); 10132352fdb0SJC Kuo else 10142352fdb0SJC Kuo dev_dbg(padctl->dev, "PLLE is already in HW control\n"); 10152352fdb0SJC Kuo 10162352fdb0SJC Kuo tegra210_aux_mux_lp0_clamp_disable(padctl); 10172352fdb0SJC Kuo 101887d66f28SThierry Reding return 0; 101987d66f28SThierry Reding } 102087d66f28SThierry Reding 10212352fdb0SJC Kuo static void __maybe_unused 10222352fdb0SJC Kuo tegra210_uphy_deinit(struct tegra_xusb_padctl *padctl) 10232352fdb0SJC Kuo { 10242352fdb0SJC Kuo tegra210_aux_mux_lp0_clamp_enable(padctl); 10252352fdb0SJC Kuo 10262352fdb0SJC Kuo if (padctl->sata) 10272352fdb0SJC Kuo tegra210_sata_uphy_disable(padctl); 10282352fdb0SJC Kuo 10292352fdb0SJC Kuo if (padctl->pcie) 10302352fdb0SJC Kuo tegra210_pex_uphy_disable(padctl); 10312352fdb0SJC Kuo } 10322352fdb0SJC Kuo 103387d66f28SThierry Reding static int tegra210_hsic_set_idle(struct tegra_xusb_padctl *padctl, 103487d66f28SThierry Reding unsigned int index, bool idle) 103587d66f28SThierry Reding { 103687d66f28SThierry Reding u32 value; 103787d66f28SThierry Reding 103887d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index)); 103987d66f28SThierry Reding 104087d66f28SThierry Reding value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 | 104187d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 | 104287d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE); 104387d66f28SThierry Reding 104487d66f28SThierry Reding if (idle) 104587d66f28SThierry Reding value |= XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 | 104687d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 | 104787d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE; 104887d66f28SThierry Reding else 104987d66f28SThierry Reding value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 | 105087d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 | 105187d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE); 105287d66f28SThierry Reding 105387d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL0(index)); 105487d66f28SThierry Reding 105587d66f28SThierry Reding return 0; 105687d66f28SThierry Reding } 105787d66f28SThierry Reding 1058*2d102148SJC Kuo static int tegra210_usb3_enable_phy_sleepwalk(struct tegra_xusb_lane *lane, 1059*2d102148SJC Kuo enum usb_device_speed speed) 1060*2d102148SJC Kuo { 1061*2d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1062*2d102148SJC Kuo int port = tegra210_usb3_lane_map(lane); 1063*2d102148SJC Kuo struct device *dev = padctl->dev; 1064*2d102148SJC Kuo u32 value; 1065*2d102148SJC Kuo 1066*2d102148SJC Kuo if (port < 0) { 1067*2d102148SJC Kuo dev_err(dev, "invalid usb3 port number\n"); 1068*2d102148SJC Kuo return -EINVAL; 1069*2d102148SJC Kuo } 1070*2d102148SJC Kuo 1071*2d102148SJC Kuo mutex_lock(&padctl->lock); 1072*2d102148SJC Kuo 1073*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 1074*2d102148SJC Kuo value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port); 1075*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 1076*2d102148SJC Kuo 1077*2d102148SJC Kuo usleep_range(100, 200); 1078*2d102148SJC Kuo 1079*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 1080*2d102148SJC Kuo value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port); 1081*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 1082*2d102148SJC Kuo 1083*2d102148SJC Kuo usleep_range(250, 350); 1084*2d102148SJC Kuo 1085*2d102148SJC Kuo mutex_unlock(&padctl->lock); 1086*2d102148SJC Kuo 1087*2d102148SJC Kuo return 0; 1088*2d102148SJC Kuo } 1089*2d102148SJC Kuo 1090*2d102148SJC Kuo static int tegra210_usb3_disable_phy_sleepwalk(struct tegra_xusb_lane *lane) 1091*2d102148SJC Kuo { 1092*2d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1093*2d102148SJC Kuo int port = tegra210_usb3_lane_map(lane); 1094*2d102148SJC Kuo struct device *dev = padctl->dev; 1095*2d102148SJC Kuo u32 value; 1096*2d102148SJC Kuo 1097*2d102148SJC Kuo if (port < 0) { 1098*2d102148SJC Kuo dev_err(dev, "invalid usb3 port number\n"); 1099*2d102148SJC Kuo return -EINVAL; 1100*2d102148SJC Kuo } 1101*2d102148SJC Kuo 1102*2d102148SJC Kuo mutex_lock(&padctl->lock); 1103*2d102148SJC Kuo 1104*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 1105*2d102148SJC Kuo value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port); 1106*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 1107*2d102148SJC Kuo 1108*2d102148SJC Kuo usleep_range(100, 200); 1109*2d102148SJC Kuo 1110*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 1111*2d102148SJC Kuo value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port); 1112*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 1113*2d102148SJC Kuo 1114*2d102148SJC Kuo mutex_unlock(&padctl->lock); 1115*2d102148SJC Kuo 1116*2d102148SJC Kuo return 0; 1117*2d102148SJC Kuo } 1118*2d102148SJC Kuo 1119*2d102148SJC Kuo static int tegra210_usb3_enable_phy_wake(struct tegra_xusb_lane *lane) 1120*2d102148SJC Kuo { 1121*2d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1122*2d102148SJC Kuo int port = tegra210_usb3_lane_map(lane); 1123*2d102148SJC Kuo struct device *dev = padctl->dev; 1124*2d102148SJC Kuo u32 value; 1125*2d102148SJC Kuo 1126*2d102148SJC Kuo if (port < 0) { 1127*2d102148SJC Kuo dev_err(dev, "invalid usb3 port number\n"); 1128*2d102148SJC Kuo return -EINVAL; 1129*2d102148SJC Kuo } 1130*2d102148SJC Kuo 1131*2d102148SJC Kuo mutex_lock(&padctl->lock); 1132*2d102148SJC Kuo 1133*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 1134*2d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 1135*2d102148SJC Kuo value |= SS_PORT_WAKEUP_EVENT(port); 1136*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 1137*2d102148SJC Kuo 1138*2d102148SJC Kuo usleep_range(10, 20); 1139*2d102148SJC Kuo 1140*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 1141*2d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 1142*2d102148SJC Kuo value |= SS_PORT_WAKE_INTERRUPT_ENABLE(port); 1143*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 1144*2d102148SJC Kuo 1145*2d102148SJC Kuo mutex_unlock(&padctl->lock); 1146*2d102148SJC Kuo 1147*2d102148SJC Kuo return 0; 1148*2d102148SJC Kuo } 1149*2d102148SJC Kuo 1150*2d102148SJC Kuo static int tegra210_usb3_disable_phy_wake(struct tegra_xusb_lane *lane) 1151*2d102148SJC Kuo { 1152*2d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1153*2d102148SJC Kuo int port = tegra210_usb3_lane_map(lane); 1154*2d102148SJC Kuo struct device *dev = padctl->dev; 1155*2d102148SJC Kuo u32 value; 1156*2d102148SJC Kuo 1157*2d102148SJC Kuo if (port < 0) { 1158*2d102148SJC Kuo dev_err(dev, "invalid usb3 port number\n"); 1159*2d102148SJC Kuo return -EINVAL; 1160*2d102148SJC Kuo } 1161*2d102148SJC Kuo 1162*2d102148SJC Kuo mutex_lock(&padctl->lock); 1163*2d102148SJC Kuo 1164*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 1165*2d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 1166*2d102148SJC Kuo value &= ~SS_PORT_WAKE_INTERRUPT_ENABLE(port); 1167*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 1168*2d102148SJC Kuo 1169*2d102148SJC Kuo usleep_range(10, 20); 1170*2d102148SJC Kuo 1171*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 1172*2d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 1173*2d102148SJC Kuo value |= SS_PORT_WAKEUP_EVENT(port); 1174*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 1175*2d102148SJC Kuo 1176*2d102148SJC Kuo mutex_unlock(&padctl->lock); 1177*2d102148SJC Kuo 1178*2d102148SJC Kuo return 0; 1179*2d102148SJC Kuo } 1180*2d102148SJC Kuo 1181*2d102148SJC Kuo static bool tegra210_usb3_phy_remote_wake_detected(struct tegra_xusb_lane *lane) 1182*2d102148SJC Kuo { 1183*2d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1184*2d102148SJC Kuo int index = tegra210_usb3_lane_map(lane); 1185*2d102148SJC Kuo u32 value; 1186*2d102148SJC Kuo 1187*2d102148SJC Kuo if (index < 0) 1188*2d102148SJC Kuo return false; 1189*2d102148SJC Kuo 1190*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 1191*2d102148SJC Kuo if ((value & SS_PORT_WAKE_INTERRUPT_ENABLE(index)) && (value & SS_PORT_WAKEUP_EVENT(index))) 1192*2d102148SJC Kuo return true; 1193*2d102148SJC Kuo 1194*2d102148SJC Kuo return false; 1195*2d102148SJC Kuo } 1196*2d102148SJC Kuo 1197*2d102148SJC Kuo static int tegra210_utmi_enable_phy_wake(struct tegra_xusb_lane *lane) 1198*2d102148SJC Kuo { 1199*2d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1200*2d102148SJC Kuo unsigned int index = lane->index; 1201*2d102148SJC Kuo u32 value; 1202*2d102148SJC Kuo 1203*2d102148SJC Kuo mutex_lock(&padctl->lock); 1204*2d102148SJC Kuo 1205*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 1206*2d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 1207*2d102148SJC Kuo value |= USB2_PORT_WAKEUP_EVENT(index); 1208*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 1209*2d102148SJC Kuo 1210*2d102148SJC Kuo usleep_range(10, 20); 1211*2d102148SJC Kuo 1212*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 1213*2d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 1214*2d102148SJC Kuo value |= USB2_PORT_WAKE_INTERRUPT_ENABLE(index); 1215*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 1216*2d102148SJC Kuo 1217*2d102148SJC Kuo mutex_unlock(&padctl->lock); 1218*2d102148SJC Kuo 1219*2d102148SJC Kuo return 0; 1220*2d102148SJC Kuo } 1221*2d102148SJC Kuo 1222*2d102148SJC Kuo static int tegra210_utmi_disable_phy_wake(struct tegra_xusb_lane *lane) 1223*2d102148SJC Kuo { 1224*2d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1225*2d102148SJC Kuo unsigned int index = lane->index; 1226*2d102148SJC Kuo u32 value; 1227*2d102148SJC Kuo 1228*2d102148SJC Kuo mutex_lock(&padctl->lock); 1229*2d102148SJC Kuo 1230*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 1231*2d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 1232*2d102148SJC Kuo value &= ~USB2_PORT_WAKE_INTERRUPT_ENABLE(index); 1233*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 1234*2d102148SJC Kuo 1235*2d102148SJC Kuo usleep_range(10, 20); 1236*2d102148SJC Kuo 1237*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 1238*2d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 1239*2d102148SJC Kuo value |= USB2_PORT_WAKEUP_EVENT(index); 1240*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 1241*2d102148SJC Kuo 1242*2d102148SJC Kuo mutex_unlock(&padctl->lock); 1243*2d102148SJC Kuo 1244*2d102148SJC Kuo return 0; 1245*2d102148SJC Kuo } 1246*2d102148SJC Kuo 1247*2d102148SJC Kuo static bool tegra210_utmi_phy_remote_wake_detected(struct tegra_xusb_lane *lane) 1248*2d102148SJC Kuo { 1249*2d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1250*2d102148SJC Kuo unsigned int index = lane->index; 1251*2d102148SJC Kuo u32 value; 1252*2d102148SJC Kuo 1253*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 1254*2d102148SJC Kuo if ((value & USB2_PORT_WAKE_INTERRUPT_ENABLE(index)) && 1255*2d102148SJC Kuo (value & USB2_PORT_WAKEUP_EVENT(index))) 1256*2d102148SJC Kuo return true; 1257*2d102148SJC Kuo 1258*2d102148SJC Kuo return false; 1259*2d102148SJC Kuo } 1260*2d102148SJC Kuo 1261*2d102148SJC Kuo static int tegra210_hsic_enable_phy_wake(struct tegra_xusb_lane *lane) 1262*2d102148SJC Kuo { 1263*2d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1264*2d102148SJC Kuo unsigned int index = lane->index; 1265*2d102148SJC Kuo u32 value; 1266*2d102148SJC Kuo 1267*2d102148SJC Kuo mutex_lock(&padctl->lock); 1268*2d102148SJC Kuo 1269*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 1270*2d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 1271*2d102148SJC Kuo value |= USB2_HSIC_PORT_WAKEUP_EVENT(index); 1272*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 1273*2d102148SJC Kuo 1274*2d102148SJC Kuo usleep_range(10, 20); 1275*2d102148SJC Kuo 1276*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 1277*2d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 1278*2d102148SJC Kuo value |= USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index); 1279*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 1280*2d102148SJC Kuo 1281*2d102148SJC Kuo mutex_unlock(&padctl->lock); 1282*2d102148SJC Kuo 1283*2d102148SJC Kuo return 0; 1284*2d102148SJC Kuo } 1285*2d102148SJC Kuo 1286*2d102148SJC Kuo static int tegra210_hsic_disable_phy_wake(struct tegra_xusb_lane *lane) 1287*2d102148SJC Kuo { 1288*2d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1289*2d102148SJC Kuo unsigned int index = lane->index; 1290*2d102148SJC Kuo u32 value; 1291*2d102148SJC Kuo 1292*2d102148SJC Kuo mutex_lock(&padctl->lock); 1293*2d102148SJC Kuo 1294*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 1295*2d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 1296*2d102148SJC Kuo value &= ~USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index); 1297*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 1298*2d102148SJC Kuo 1299*2d102148SJC Kuo usleep_range(10, 20); 1300*2d102148SJC Kuo 1301*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 1302*2d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 1303*2d102148SJC Kuo value |= USB2_HSIC_PORT_WAKEUP_EVENT(index); 1304*2d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 1305*2d102148SJC Kuo 1306*2d102148SJC Kuo mutex_unlock(&padctl->lock); 1307*2d102148SJC Kuo 1308*2d102148SJC Kuo return 0; 1309*2d102148SJC Kuo } 1310*2d102148SJC Kuo 1311*2d102148SJC Kuo static bool tegra210_hsic_phy_remote_wake_detected(struct tegra_xusb_lane *lane) 1312*2d102148SJC Kuo { 1313*2d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1314*2d102148SJC Kuo unsigned int index = lane->index; 1315*2d102148SJC Kuo u32 value; 1316*2d102148SJC Kuo 1317*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 1318*2d102148SJC Kuo if ((value & USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index)) && 1319*2d102148SJC Kuo (value & USB2_HSIC_PORT_WAKEUP_EVENT(index))) 1320*2d102148SJC Kuo return true; 1321*2d102148SJC Kuo 1322*2d102148SJC Kuo return false; 1323*2d102148SJC Kuo } 1324*2d102148SJC Kuo 1325*2d102148SJC Kuo #define padctl_pmc_readl(_priv, _offset) \ 1326*2d102148SJC Kuo ({ \ 1327*2d102148SJC Kuo u32 value; \ 1328*2d102148SJC Kuo WARN(regmap_read(_priv->regmap, _offset, &value), "read %s failed\n", #_offset);\ 1329*2d102148SJC Kuo value; \ 1330*2d102148SJC Kuo }) 1331*2d102148SJC Kuo 1332*2d102148SJC Kuo #define padctl_pmc_writel(_priv, _value, _offset) \ 1333*2d102148SJC Kuo WARN(regmap_write(_priv->regmap, _offset, _value), "write %s failed\n", #_offset) 1334*2d102148SJC Kuo 1335*2d102148SJC Kuo static int tegra210_pmc_utmi_enable_phy_sleepwalk(struct tegra_xusb_lane *lane, 1336*2d102148SJC Kuo enum usb_device_speed speed) 1337*2d102148SJC Kuo { 1338*2d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1339*2d102148SJC Kuo struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl); 1340*2d102148SJC Kuo unsigned int port = lane->index; 1341*2d102148SJC Kuo u32 value, tctrl, pctrl, rpd_ctrl; 1342*2d102148SJC Kuo 1343*2d102148SJC Kuo if (!priv->regmap) 1344*2d102148SJC Kuo return -EOPNOTSUPP; 1345*2d102148SJC Kuo 1346*2d102148SJC Kuo if (speed > USB_SPEED_HIGH) 1347*2d102148SJC Kuo return -EINVAL; 1348*2d102148SJC Kuo 1349*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 1350*2d102148SJC Kuo tctrl = TCTRL_VALUE(value); 1351*2d102148SJC Kuo pctrl = PCTRL_VALUE(value); 1352*2d102148SJC Kuo 1353*2d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port)); 1354*2d102148SJC Kuo rpd_ctrl = RPD_CTRL_VALUE(value); 1355*2d102148SJC Kuo 1356*2d102148SJC Kuo /* ensure sleepwalk logic is disabled */ 1357*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1358*2d102148SJC Kuo value &= ~UTMIP_MASTER_ENABLE(port); 1359*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1360*2d102148SJC Kuo 1361*2d102148SJC Kuo /* ensure sleepwalk logics are in low power mode */ 1362*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG); 1363*2d102148SJC Kuo value |= UTMIP_PWR(port); 1364*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG); 1365*2d102148SJC Kuo 1366*2d102148SJC Kuo /* set debounce time */ 1367*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL); 1368*2d102148SJC Kuo value &= ~UTMIP_LINE_DEB_CNT(~0); 1369*2d102148SJC Kuo value |= UTMIP_LINE_DEB_CNT(0x1); 1370*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_DEBOUNCE_DEL); 1371*2d102148SJC Kuo 1372*2d102148SJC Kuo /* ensure fake events of sleepwalk logic are desiabled */ 1373*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_FAKE(port)); 1374*2d102148SJC Kuo value &= ~(UTMIP_FAKE_USBOP_VAL(port) | UTMIP_FAKE_USBON_VAL(port) | 1375*2d102148SJC Kuo UTMIP_FAKE_USBOP_EN(port) | UTMIP_FAKE_USBON_EN(port)); 1376*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_FAKE(port)); 1377*2d102148SJC Kuo 1378*2d102148SJC Kuo /* ensure wake events of sleepwalk logic are not latched */ 1379*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP); 1380*2d102148SJC Kuo value &= ~UTMIP_LINE_WAKEUP_EN(port); 1381*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP); 1382*2d102148SJC Kuo 1383*2d102148SJC Kuo /* disable wake event triggers of sleepwalk logic */ 1384*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1385*2d102148SJC Kuo value &= ~UTMIP_WAKE_VAL(port, ~0); 1386*2d102148SJC Kuo value |= UTMIP_WAKE_VAL_NONE(port); 1387*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1388*2d102148SJC Kuo 1389*2d102148SJC Kuo /* power down the line state detectors of the pad */ 1390*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_AO); 1391*2d102148SJC Kuo value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port)); 1392*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_AO); 1393*2d102148SJC Kuo 1394*2d102148SJC Kuo /* save state per speed */ 1395*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SAVED_STATE(port)); 1396*2d102148SJC Kuo value &= ~SPEED(port, ~0); 1397*2d102148SJC Kuo 1398*2d102148SJC Kuo switch (speed) { 1399*2d102148SJC Kuo case USB_SPEED_HIGH: 1400*2d102148SJC Kuo value |= UTMI_HS(port); 1401*2d102148SJC Kuo break; 1402*2d102148SJC Kuo 1403*2d102148SJC Kuo case USB_SPEED_FULL: 1404*2d102148SJC Kuo value |= UTMI_FS(port); 1405*2d102148SJC Kuo break; 1406*2d102148SJC Kuo 1407*2d102148SJC Kuo case USB_SPEED_LOW: 1408*2d102148SJC Kuo value |= UTMI_LS(port); 1409*2d102148SJC Kuo break; 1410*2d102148SJC Kuo 1411*2d102148SJC Kuo default: 1412*2d102148SJC Kuo value |= UTMI_RST(port); 1413*2d102148SJC Kuo break; 1414*2d102148SJC Kuo } 1415*2d102148SJC Kuo 1416*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SAVED_STATE(port)); 1417*2d102148SJC Kuo 1418*2d102148SJC Kuo /* enable the trigger of the sleepwalk logic */ 1419*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port)); 1420*2d102148SJC Kuo value |= UTMIP_LINEVAL_WALK_EN(port); 1421*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port)); 1422*2d102148SJC Kuo 1423*2d102148SJC Kuo /* 1424*2d102148SJC Kuo * Reset the walk pointer and clear the alarm of the sleepwalk logic, 1425*2d102148SJC Kuo * as well as capture the configuration of the USB2.0 pad. 1426*2d102148SJC Kuo */ 1427*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS); 1428*2d102148SJC Kuo value |= UTMIP_CLR_WALK_PTR(port) | UTMIP_CLR_WAKE_ALARM(port) | UTMIP_CAP_CFG(port); 1429*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS); 1430*2d102148SJC Kuo 1431*2d102148SJC Kuo /* program electrical parameters read from XUSB PADCTL */ 1432*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_TERM_PAD_CFG); 1433*2d102148SJC Kuo value &= ~(TCTRL_VAL(~0) | PCTRL_VAL(~0)); 1434*2d102148SJC Kuo value |= (TCTRL_VAL(tctrl) | PCTRL_VAL(pctrl)); 1435*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_TERM_PAD_CFG); 1436*2d102148SJC Kuo 1437*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_PAD_CFGX(port)); 1438*2d102148SJC Kuo value &= ~RPD_CTRL_PX(~0); 1439*2d102148SJC Kuo value |= RPD_CTRL_PX(rpd_ctrl); 1440*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_PAD_CFGX(port)); 1441*2d102148SJC Kuo 1442*2d102148SJC Kuo /* 1443*2d102148SJC Kuo * Set up the pull-ups and pull-downs of the signals during the four 1444*2d102148SJC Kuo * stages of sleepwalk. If a device is connected, program sleepwalk 1445*2d102148SJC Kuo * logic to maintain a J and keep driving K upon seeing remote wake. 1446*2d102148SJC Kuo */ 1447*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_SLEEPWALK_PX(port)); 1448*2d102148SJC Kuo value = UTMIP_USBOP_RPD_A | UTMIP_USBOP_RPD_B | UTMIP_USBOP_RPD_C | UTMIP_USBOP_RPD_D; 1449*2d102148SJC Kuo value |= UTMIP_USBON_RPD_A | UTMIP_USBON_RPD_B | UTMIP_USBON_RPD_C | UTMIP_USBON_RPD_D; 1450*2d102148SJC Kuo 1451*2d102148SJC Kuo switch (speed) { 1452*2d102148SJC Kuo case USB_SPEED_HIGH: 1453*2d102148SJC Kuo case USB_SPEED_FULL: 1454*2d102148SJC Kuo /* J state: D+/D- = high/low, K state: D+/D- = low/high */ 1455*2d102148SJC Kuo value |= UTMIP_HIGHZ_A; 1456*2d102148SJC Kuo value |= UTMIP_AP_A; 1457*2d102148SJC Kuo value |= UTMIP_AN_B | UTMIP_AN_C | UTMIP_AN_D; 1458*2d102148SJC Kuo break; 1459*2d102148SJC Kuo 1460*2d102148SJC Kuo case USB_SPEED_LOW: 1461*2d102148SJC Kuo /* J state: D+/D- = low/high, K state: D+/D- = high/low */ 1462*2d102148SJC Kuo value |= UTMIP_HIGHZ_A; 1463*2d102148SJC Kuo value |= UTMIP_AN_A; 1464*2d102148SJC Kuo value |= UTMIP_AP_B | UTMIP_AP_C | UTMIP_AP_D; 1465*2d102148SJC Kuo break; 1466*2d102148SJC Kuo 1467*2d102148SJC Kuo default: 1468*2d102148SJC Kuo value |= UTMIP_HIGHZ_A | UTMIP_HIGHZ_B | UTMIP_HIGHZ_C | UTMIP_HIGHZ_D; 1469*2d102148SJC Kuo break; 1470*2d102148SJC Kuo } 1471*2d102148SJC Kuo 1472*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_SLEEPWALK_PX(port)); 1473*2d102148SJC Kuo 1474*2d102148SJC Kuo /* power up the line state detectors of the pad */ 1475*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_AO); 1476*2d102148SJC Kuo value &= ~(USBOP_VAL_PD(port) | USBON_VAL_PD(port)); 1477*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_AO); 1478*2d102148SJC Kuo 1479*2d102148SJC Kuo usleep_range(50, 100); 1480*2d102148SJC Kuo 1481*2d102148SJC Kuo /* switch the electric control of the USB2.0 pad to PMC */ 1482*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1483*2d102148SJC Kuo value |= UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) | UTMIP_TCTRL_USE_PMC(port); 1484*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1485*2d102148SJC Kuo 1486*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1); 1487*2d102148SJC Kuo value |= UTMIP_RPD_CTRL_USE_PMC_PX(port) | UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port); 1488*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1); 1489*2d102148SJC Kuo 1490*2d102148SJC Kuo /* set the wake signaling trigger events */ 1491*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1492*2d102148SJC Kuo value &= ~UTMIP_WAKE_VAL(port, ~0); 1493*2d102148SJC Kuo value |= UTMIP_WAKE_VAL_ANY(port); 1494*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1495*2d102148SJC Kuo 1496*2d102148SJC Kuo /* enable the wake detection */ 1497*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1498*2d102148SJC Kuo value |= UTMIP_MASTER_ENABLE(port); 1499*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1500*2d102148SJC Kuo 1501*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP); 1502*2d102148SJC Kuo value |= UTMIP_LINE_WAKEUP_EN(port); 1503*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP); 1504*2d102148SJC Kuo 1505*2d102148SJC Kuo return 0; 1506*2d102148SJC Kuo } 1507*2d102148SJC Kuo 1508*2d102148SJC Kuo static int tegra210_pmc_utmi_disable_phy_sleepwalk(struct tegra_xusb_lane *lane) 1509*2d102148SJC Kuo { 1510*2d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1511*2d102148SJC Kuo struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl); 1512*2d102148SJC Kuo unsigned int port = lane->index; 1513*2d102148SJC Kuo u32 value; 1514*2d102148SJC Kuo 1515*2d102148SJC Kuo if (!priv->regmap) 1516*2d102148SJC Kuo return -EOPNOTSUPP; 1517*2d102148SJC Kuo 1518*2d102148SJC Kuo /* disable the wake detection */ 1519*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1520*2d102148SJC Kuo value &= ~UTMIP_MASTER_ENABLE(port); 1521*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1522*2d102148SJC Kuo 1523*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP); 1524*2d102148SJC Kuo value &= ~UTMIP_LINE_WAKEUP_EN(port); 1525*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP); 1526*2d102148SJC Kuo 1527*2d102148SJC Kuo /* switch the electric control of the USB2.0 pad to XUSB or USB2 */ 1528*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1529*2d102148SJC Kuo value &= ~(UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) | 1530*2d102148SJC Kuo UTMIP_TCTRL_USE_PMC(port)); 1531*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1532*2d102148SJC Kuo 1533*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1); 1534*2d102148SJC Kuo value &= ~(UTMIP_RPD_CTRL_USE_PMC_PX(port) | UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port)); 1535*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1); 1536*2d102148SJC Kuo 1537*2d102148SJC Kuo /* disable wake event triggers of sleepwalk logic */ 1538*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1539*2d102148SJC Kuo value &= ~UTMIP_WAKE_VAL(port, ~0); 1540*2d102148SJC Kuo value |= UTMIP_WAKE_VAL_NONE(port); 1541*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 1542*2d102148SJC Kuo 1543*2d102148SJC Kuo /* power down the line state detectors of the port */ 1544*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_AO); 1545*2d102148SJC Kuo value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port)); 1546*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_AO); 1547*2d102148SJC Kuo 1548*2d102148SJC Kuo /* clear alarm of the sleepwalk logic */ 1549*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS); 1550*2d102148SJC Kuo value |= UTMIP_CLR_WAKE_ALARM(port); 1551*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS); 1552*2d102148SJC Kuo 1553*2d102148SJC Kuo return 0; 1554*2d102148SJC Kuo } 1555*2d102148SJC Kuo 1556*2d102148SJC Kuo static int tegra210_pmc_hsic_enable_phy_sleepwalk(struct tegra_xusb_lane *lane, 1557*2d102148SJC Kuo enum usb_device_speed speed) 1558*2d102148SJC Kuo { 1559*2d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1560*2d102148SJC Kuo struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl); 1561*2d102148SJC Kuo u32 value; 1562*2d102148SJC Kuo 1563*2d102148SJC Kuo if (!priv->regmap) 1564*2d102148SJC Kuo return -EOPNOTSUPP; 1565*2d102148SJC Kuo 1566*2d102148SJC Kuo /* ensure sleepwalk logic is disabled */ 1567*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG); 1568*2d102148SJC Kuo value &= ~UHSIC_MASTER_ENABLE; 1569*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG); 1570*2d102148SJC Kuo 1571*2d102148SJC Kuo /* ensure sleepwalk logics are in low power mode */ 1572*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG); 1573*2d102148SJC Kuo value |= UHSIC_PWR; 1574*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG); 1575*2d102148SJC Kuo 1576*2d102148SJC Kuo /* set debounce time */ 1577*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL); 1578*2d102148SJC Kuo value &= ~UHSIC_LINE_DEB_CNT(~0); 1579*2d102148SJC Kuo value |= UHSIC_LINE_DEB_CNT(0x1); 1580*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_DEBOUNCE_DEL); 1581*2d102148SJC Kuo 1582*2d102148SJC Kuo /* ensure fake events of sleepwalk logic are desiabled */ 1583*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_FAKE); 1584*2d102148SJC Kuo value &= ~(UHSIC_FAKE_STROBE_VAL | UHSIC_FAKE_DATA_VAL | 1585*2d102148SJC Kuo UHSIC_FAKE_STROBE_EN | UHSIC_FAKE_DATA_EN); 1586*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_FAKE); 1587*2d102148SJC Kuo 1588*2d102148SJC Kuo /* ensure wake events of sleepwalk logic are not latched */ 1589*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP); 1590*2d102148SJC Kuo value &= ~UHSIC_LINE_WAKEUP_EN; 1591*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP); 1592*2d102148SJC Kuo 1593*2d102148SJC Kuo /* disable wake event triggers of sleepwalk logic */ 1594*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG); 1595*2d102148SJC Kuo value &= ~UHSIC_WAKE_VAL(~0); 1596*2d102148SJC Kuo value |= UHSIC_WAKE_VAL_NONE; 1597*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG); 1598*2d102148SJC Kuo 1599*2d102148SJC Kuo /* power down the line state detectors of the port */ 1600*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_AO); 1601*2d102148SJC Kuo value |= STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD; 1602*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_AO); 1603*2d102148SJC Kuo 1604*2d102148SJC Kuo /* save state, HSIC always comes up as HS */ 1605*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SAVED_STATE); 1606*2d102148SJC Kuo value &= ~UHSIC_MODE(~0); 1607*2d102148SJC Kuo value |= UHSIC_HS; 1608*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SAVED_STATE); 1609*2d102148SJC Kuo 1610*2d102148SJC Kuo /* enable the trigger of the sleepwalk logic */ 1611*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_CFG); 1612*2d102148SJC Kuo value |= UHSIC_WAKE_WALK_EN | UHSIC_LINEVAL_WALK_EN; 1613*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_CFG); 1614*2d102148SJC Kuo 1615*2d102148SJC Kuo /* 1616*2d102148SJC Kuo * Reset the walk pointer and clear the alarm of the sleepwalk logic, 1617*2d102148SJC Kuo * as well as capture the configuration of the USB2.0 port. 1618*2d102148SJC Kuo */ 1619*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS); 1620*2d102148SJC Kuo value |= UHSIC_CLR_WALK_PTR | UHSIC_CLR_WAKE_ALARM; 1621*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS); 1622*2d102148SJC Kuo 1623*2d102148SJC Kuo /* 1624*2d102148SJC Kuo * Set up the pull-ups and pull-downs of the signals during the four 1625*2d102148SJC Kuo * stages of sleepwalk. Maintain a HSIC IDLE and keep driving HSIC 1626*2d102148SJC Kuo * RESUME upon remote wake. 1627*2d102148SJC Kuo */ 1628*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_P0); 1629*2d102148SJC Kuo value = UHSIC_DATA0_RPD_A | UHSIC_DATA0_RPU_B | UHSIC_DATA0_RPU_C | UHSIC_DATA0_RPU_D | 1630*2d102148SJC Kuo UHSIC_STROBE_RPU_A | UHSIC_STROBE_RPD_B | UHSIC_STROBE_RPD_C | UHSIC_STROBE_RPD_D; 1631*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_P0); 1632*2d102148SJC Kuo 1633*2d102148SJC Kuo /* power up the line state detectors of the port */ 1634*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_AO); 1635*2d102148SJC Kuo value &= ~(STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD); 1636*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_AO); 1637*2d102148SJC Kuo 1638*2d102148SJC Kuo usleep_range(50, 100); 1639*2d102148SJC Kuo 1640*2d102148SJC Kuo /* set the wake signaling trigger events */ 1641*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG); 1642*2d102148SJC Kuo value &= ~UHSIC_WAKE_VAL(~0); 1643*2d102148SJC Kuo value |= UHSIC_WAKE_VAL_SD10; 1644*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG); 1645*2d102148SJC Kuo 1646*2d102148SJC Kuo /* enable the wake detection */ 1647*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG); 1648*2d102148SJC Kuo value |= UHSIC_MASTER_ENABLE; 1649*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG); 1650*2d102148SJC Kuo 1651*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP); 1652*2d102148SJC Kuo value |= UHSIC_LINE_WAKEUP_EN; 1653*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP); 1654*2d102148SJC Kuo 1655*2d102148SJC Kuo return 0; 1656*2d102148SJC Kuo } 1657*2d102148SJC Kuo 1658*2d102148SJC Kuo static int tegra210_pmc_hsic_disable_phy_sleepwalk(struct tegra_xusb_lane *lane) 1659*2d102148SJC Kuo { 1660*2d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1661*2d102148SJC Kuo struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl); 1662*2d102148SJC Kuo u32 value; 1663*2d102148SJC Kuo 1664*2d102148SJC Kuo if (!priv->regmap) 1665*2d102148SJC Kuo return -EOPNOTSUPP; 1666*2d102148SJC Kuo 1667*2d102148SJC Kuo /* disable the wake detection */ 1668*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG); 1669*2d102148SJC Kuo value &= ~UHSIC_MASTER_ENABLE; 1670*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG); 1671*2d102148SJC Kuo 1672*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP); 1673*2d102148SJC Kuo value &= ~UHSIC_LINE_WAKEUP_EN; 1674*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP); 1675*2d102148SJC Kuo 1676*2d102148SJC Kuo /* disable wake event triggers of sleepwalk logic */ 1677*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG); 1678*2d102148SJC Kuo value &= ~UHSIC_WAKE_VAL(~0); 1679*2d102148SJC Kuo value |= UHSIC_WAKE_VAL_NONE; 1680*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG); 1681*2d102148SJC Kuo 1682*2d102148SJC Kuo /* power down the line state detectors of the port */ 1683*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_AO); 1684*2d102148SJC Kuo value |= STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD; 1685*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_AO); 1686*2d102148SJC Kuo 1687*2d102148SJC Kuo /* clear alarm of the sleepwalk logic */ 1688*2d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS); 1689*2d102148SJC Kuo value |= UHSIC_CLR_WAKE_ALARM; 1690*2d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS); 1691*2d102148SJC Kuo 1692*2d102148SJC Kuo return 0; 1693*2d102148SJC Kuo } 1694*2d102148SJC Kuo 169587d66f28SThierry Reding static int tegra210_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl, 169687d66f28SThierry Reding unsigned int index, bool enable) 169787d66f28SThierry Reding { 169887d66f28SThierry Reding struct tegra_xusb_port *port; 169987d66f28SThierry Reding struct tegra_xusb_lane *lane; 170087d66f28SThierry Reding u32 value, offset; 170187d66f28SThierry Reding 170287d66f28SThierry Reding port = tegra_xusb_find_port(padctl, "usb3", index); 170387d66f28SThierry Reding if (!port) 170487d66f28SThierry Reding return -ENODEV; 170587d66f28SThierry Reding 170687d66f28SThierry Reding lane = port->lane; 170787d66f28SThierry Reding 170887d66f28SThierry Reding if (lane->pad == padctl->pcie) 170987d66f28SThierry Reding offset = XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL1(lane->index); 171087d66f28SThierry Reding else 171187d66f28SThierry Reding offset = XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1; 171287d66f28SThierry Reding 171387d66f28SThierry Reding value = padctl_readl(padctl, offset); 171487d66f28SThierry Reding 171587d66f28SThierry Reding value &= ~((XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_MASK << 171687d66f28SThierry Reding XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT) | 171787d66f28SThierry Reding XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN | 171887d66f28SThierry Reding XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD); 171987d66f28SThierry Reding 172087d66f28SThierry Reding if (!enable) { 172187d66f28SThierry Reding value |= (XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_VAL << 172287d66f28SThierry Reding XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT) | 172387d66f28SThierry Reding XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN | 172487d66f28SThierry Reding XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD; 172587d66f28SThierry Reding } 172687d66f28SThierry Reding 172787d66f28SThierry Reding padctl_writel(padctl, value, offset); 172887d66f28SThierry Reding 172987d66f28SThierry Reding return 0; 173087d66f28SThierry Reding } 173187d66f28SThierry Reding 173287d66f28SThierry Reding #define TEGRA210_LANE(_name, _offset, _shift, _mask, _type) \ 173387d66f28SThierry Reding { \ 173487d66f28SThierry Reding .name = _name, \ 173587d66f28SThierry Reding .offset = _offset, \ 173687d66f28SThierry Reding .shift = _shift, \ 173787d66f28SThierry Reding .mask = _mask, \ 173887d66f28SThierry Reding .num_funcs = ARRAY_SIZE(tegra210_##_type##_functions), \ 173987d66f28SThierry Reding .funcs = tegra210_##_type##_functions, \ 174087d66f28SThierry Reding } 174187d66f28SThierry Reding 174287d66f28SThierry Reding static const char *tegra210_usb2_functions[] = { 174387d66f28SThierry Reding "snps", 174487d66f28SThierry Reding "xusb", 174587d66f28SThierry Reding "uart" 174687d66f28SThierry Reding }; 174787d66f28SThierry Reding 174887d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_usb2_lanes[] = { 174987d66f28SThierry Reding TEGRA210_LANE("usb2-0", 0x004, 0, 0x3, usb2), 175087d66f28SThierry Reding TEGRA210_LANE("usb2-1", 0x004, 2, 0x3, usb2), 175187d66f28SThierry Reding TEGRA210_LANE("usb2-2", 0x004, 4, 0x3, usb2), 175287d66f28SThierry Reding TEGRA210_LANE("usb2-3", 0x004, 6, 0x3, usb2), 175387d66f28SThierry Reding }; 175487d66f28SThierry Reding 175587d66f28SThierry Reding static struct tegra_xusb_lane * 175687d66f28SThierry Reding tegra210_usb2_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, 175787d66f28SThierry Reding unsigned int index) 175887d66f28SThierry Reding { 175987d66f28SThierry Reding struct tegra_xusb_usb2_lane *usb2; 176087d66f28SThierry Reding int err; 176187d66f28SThierry Reding 176287d66f28SThierry Reding usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL); 176387d66f28SThierry Reding if (!usb2) 176487d66f28SThierry Reding return ERR_PTR(-ENOMEM); 176587d66f28SThierry Reding 176687d66f28SThierry Reding INIT_LIST_HEAD(&usb2->base.list); 176787d66f28SThierry Reding usb2->base.soc = &pad->soc->lanes[index]; 176887d66f28SThierry Reding usb2->base.index = index; 176987d66f28SThierry Reding usb2->base.pad = pad; 177087d66f28SThierry Reding usb2->base.np = np; 177187d66f28SThierry Reding 177287d66f28SThierry Reding err = tegra_xusb_lane_parse_dt(&usb2->base, np); 177387d66f28SThierry Reding if (err < 0) { 177487d66f28SThierry Reding kfree(usb2); 177587d66f28SThierry Reding return ERR_PTR(err); 177687d66f28SThierry Reding } 177787d66f28SThierry Reding 177887d66f28SThierry Reding return &usb2->base; 177987d66f28SThierry Reding } 178087d66f28SThierry Reding 178187d66f28SThierry Reding static void tegra210_usb2_lane_remove(struct tegra_xusb_lane *lane) 178287d66f28SThierry Reding { 178387d66f28SThierry Reding struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); 178487d66f28SThierry Reding 178587d66f28SThierry Reding kfree(usb2); 178687d66f28SThierry Reding } 178787d66f28SThierry Reding 178887d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_usb2_lane_ops = { 178987d66f28SThierry Reding .probe = tegra210_usb2_lane_probe, 179087d66f28SThierry Reding .remove = tegra210_usb2_lane_remove, 1791*2d102148SJC Kuo .enable_phy_sleepwalk = tegra210_pmc_utmi_enable_phy_sleepwalk, 1792*2d102148SJC Kuo .disable_phy_sleepwalk = tegra210_pmc_utmi_disable_phy_sleepwalk, 1793*2d102148SJC Kuo .enable_phy_wake = tegra210_utmi_enable_phy_wake, 1794*2d102148SJC Kuo .disable_phy_wake = tegra210_utmi_disable_phy_wake, 1795*2d102148SJC Kuo .remote_wake_detected = tegra210_utmi_phy_remote_wake_detected, 179687d66f28SThierry Reding }; 179787d66f28SThierry Reding 179887d66f28SThierry Reding static int tegra210_usb2_phy_init(struct phy *phy) 179987d66f28SThierry Reding { 180087d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 180187d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 180287d66f28SThierry Reding u32 value; 180387d66f28SThierry Reding 180487d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX); 180587d66f28SThierry Reding value &= ~(XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK << 180687d66f28SThierry Reding XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT); 180787d66f28SThierry Reding value |= XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB << 180887d66f28SThierry Reding XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT; 180987d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX); 181087d66f28SThierry Reding 18112352fdb0SJC Kuo return 0; 181287d66f28SThierry Reding } 181387d66f28SThierry Reding 181487d66f28SThierry Reding static int tegra210_usb2_phy_exit(struct phy *phy) 181587d66f28SThierry Reding { 18162352fdb0SJC Kuo return 0; 181787d66f28SThierry Reding } 181887d66f28SThierry Reding 1819de792a6dSNagarjuna Kristam static int tegra210_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl, 1820de792a6dSNagarjuna Kristam bool status) 1821de792a6dSNagarjuna Kristam { 1822de792a6dSNagarjuna Kristam u32 value; 1823de792a6dSNagarjuna Kristam 1824de792a6dSNagarjuna Kristam dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear"); 1825de792a6dSNagarjuna Kristam 1826de792a6dSNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID); 1827de792a6dSNagarjuna Kristam 1828de792a6dSNagarjuna Kristam if (status) { 1829de792a6dSNagarjuna Kristam value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON; 1830de792a6dSNagarjuna Kristam value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK << 1831de792a6dSNagarjuna Kristam XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT); 1832de792a6dSNagarjuna Kristam value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING << 1833de792a6dSNagarjuna Kristam XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT; 1834de792a6dSNagarjuna Kristam } else { 1835de792a6dSNagarjuna Kristam value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON; 1836de792a6dSNagarjuna Kristam } 1837de792a6dSNagarjuna Kristam 1838de792a6dSNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID); 1839de792a6dSNagarjuna Kristam 1840de792a6dSNagarjuna Kristam return 0; 1841de792a6dSNagarjuna Kristam } 1842de792a6dSNagarjuna Kristam 1843de792a6dSNagarjuna Kristam static int tegra210_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl, 1844de792a6dSNagarjuna Kristam bool status) 1845de792a6dSNagarjuna Kristam { 1846de792a6dSNagarjuna Kristam u32 value; 1847de792a6dSNagarjuna Kristam 1848de792a6dSNagarjuna Kristam dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear"); 1849de792a6dSNagarjuna Kristam 1850de792a6dSNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID); 1851de792a6dSNagarjuna Kristam 1852de792a6dSNagarjuna Kristam if (status) { 1853de792a6dSNagarjuna Kristam if (value & XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON) { 1854de792a6dSNagarjuna Kristam value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON; 1855de792a6dSNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID); 1856de792a6dSNagarjuna Kristam usleep_range(1000, 2000); 1857de792a6dSNagarjuna Kristam 1858de792a6dSNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID); 1859de792a6dSNagarjuna Kristam } 1860de792a6dSNagarjuna Kristam 1861de792a6dSNagarjuna Kristam value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK << 1862de792a6dSNagarjuna Kristam XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT); 1863de792a6dSNagarjuna Kristam value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED << 1864de792a6dSNagarjuna Kristam XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT; 1865de792a6dSNagarjuna Kristam } else { 1866de792a6dSNagarjuna Kristam value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK << 1867de792a6dSNagarjuna Kristam XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT); 1868de792a6dSNagarjuna Kristam value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING << 1869de792a6dSNagarjuna Kristam XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT; 1870de792a6dSNagarjuna Kristam } 1871de792a6dSNagarjuna Kristam 1872de792a6dSNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID); 1873de792a6dSNagarjuna Kristam 1874de792a6dSNagarjuna Kristam return 0; 1875de792a6dSNagarjuna Kristam } 1876de792a6dSNagarjuna Kristam 1877de792a6dSNagarjuna Kristam static int tegra210_usb2_phy_set_mode(struct phy *phy, enum phy_mode mode, 1878de792a6dSNagarjuna Kristam int submode) 1879de792a6dSNagarjuna Kristam { 1880de792a6dSNagarjuna Kristam struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 1881de792a6dSNagarjuna Kristam struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1882de792a6dSNagarjuna Kristam struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl, 1883de792a6dSNagarjuna Kristam lane->index); 1884de792a6dSNagarjuna Kristam int err = 0; 1885de792a6dSNagarjuna Kristam 1886de792a6dSNagarjuna Kristam mutex_lock(&padctl->lock); 1887de792a6dSNagarjuna Kristam 1888de792a6dSNagarjuna Kristam dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode); 1889de792a6dSNagarjuna Kristam 1890de792a6dSNagarjuna Kristam if (mode == PHY_MODE_USB_OTG) { 1891de792a6dSNagarjuna Kristam if (submode == USB_ROLE_HOST) { 1892de792a6dSNagarjuna Kristam tegra210_xusb_padctl_id_override(padctl, true); 1893de792a6dSNagarjuna Kristam 1894de792a6dSNagarjuna Kristam err = regulator_enable(port->supply); 1895de792a6dSNagarjuna Kristam } else if (submode == USB_ROLE_DEVICE) { 1896de792a6dSNagarjuna Kristam tegra210_xusb_padctl_vbus_override(padctl, true); 1897de792a6dSNagarjuna Kristam } else if (submode == USB_ROLE_NONE) { 1898de792a6dSNagarjuna Kristam /* 1899de792a6dSNagarjuna Kristam * When port is peripheral only or role transitions to 1900de792a6dSNagarjuna Kristam * USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not 1901de792a6dSNagarjuna Kristam * be enabled. 1902de792a6dSNagarjuna Kristam */ 1903de792a6dSNagarjuna Kristam if (regulator_is_enabled(port->supply)) 1904de792a6dSNagarjuna Kristam regulator_disable(port->supply); 1905de792a6dSNagarjuna Kristam 1906de792a6dSNagarjuna Kristam tegra210_xusb_padctl_id_override(padctl, false); 1907de792a6dSNagarjuna Kristam tegra210_xusb_padctl_vbus_override(padctl, false); 1908de792a6dSNagarjuna Kristam } 1909de792a6dSNagarjuna Kristam } 1910de792a6dSNagarjuna Kristam 1911de792a6dSNagarjuna Kristam mutex_unlock(&padctl->lock); 1912de792a6dSNagarjuna Kristam 1913de792a6dSNagarjuna Kristam return err; 1914de792a6dSNagarjuna Kristam } 1915de792a6dSNagarjuna Kristam 191687d66f28SThierry Reding static int tegra210_usb2_phy_power_on(struct phy *phy) 191787d66f28SThierry Reding { 191887d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 191987d66f28SThierry Reding struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); 192087d66f28SThierry Reding struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad); 192187d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 192287d66f28SThierry Reding struct tegra210_xusb_padctl *priv; 192387d66f28SThierry Reding struct tegra_xusb_usb2_port *port; 192487d66f28SThierry Reding unsigned int index = lane->index; 192587d66f28SThierry Reding u32 value; 192687d66f28SThierry Reding int err; 192787d66f28SThierry Reding 192887d66f28SThierry Reding port = tegra_xusb_find_usb2_port(padctl, index); 192987d66f28SThierry Reding if (!port) { 193087d66f28SThierry Reding dev_err(&phy->dev, "no port found for USB2 lane %u\n", index); 193187d66f28SThierry Reding return -ENODEV; 193287d66f28SThierry Reding } 193387d66f28SThierry Reding 193487d66f28SThierry Reding priv = to_tegra210_xusb_padctl(padctl); 193587d66f28SThierry Reding 1936a5be28c3SNagarjuna Kristam if (port->usb3_port_fake != -1) { 1937a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); 1938a5be28c3SNagarjuna Kristam value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK( 1939a5be28c3SNagarjuna Kristam port->usb3_port_fake); 1940a5be28c3SNagarjuna Kristam value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP( 1941a5be28c3SNagarjuna Kristam port->usb3_port_fake, index); 1942a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP); 1943a5be28c3SNagarjuna Kristam 1944a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 1945a5be28c3SNagarjuna Kristam value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN( 1946a5be28c3SNagarjuna Kristam port->usb3_port_fake); 1947a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 1948a5be28c3SNagarjuna Kristam 1949a5be28c3SNagarjuna Kristam usleep_range(100, 200); 1950a5be28c3SNagarjuna Kristam 1951a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 1952a5be28c3SNagarjuna Kristam value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY( 1953a5be28c3SNagarjuna Kristam port->usb3_port_fake); 1954a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 1955a5be28c3SNagarjuna Kristam 1956a5be28c3SNagarjuna Kristam usleep_range(100, 200); 1957a5be28c3SNagarjuna Kristam 1958a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 1959a5be28c3SNagarjuna Kristam value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN( 1960a5be28c3SNagarjuna Kristam port->usb3_port_fake); 1961a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 1962a5be28c3SNagarjuna Kristam } 1963a5be28c3SNagarjuna Kristam 196487d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 196587d66f28SThierry Reding value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK << 196687d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) | 196787d66f28SThierry Reding (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK << 196887d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT)); 196987d66f28SThierry Reding value |= (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL << 197087d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT); 197187d66f28SThierry Reding 197287d66f28SThierry Reding if (tegra_sku_info.revision < TEGRA_REVISION_A02) 197387d66f28SThierry Reding value |= 197487d66f28SThierry Reding (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_VAL << 197587d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT); 197687d66f28SThierry Reding 197787d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 197887d66f28SThierry Reding 197987d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP); 198087d66f28SThierry Reding value &= ~XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(index); 1981ac25b6e9SNagarjuna Kristam if (port->mode == USB_DR_MODE_UNKNOWN) 1982ac25b6e9SNagarjuna Kristam value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DISABLED(index); 1983ac25b6e9SNagarjuna Kristam else if (port->mode == USB_DR_MODE_PERIPHERAL) 1984ac25b6e9SNagarjuna Kristam value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DEVICE(index); 1985ac25b6e9SNagarjuna Kristam else if (port->mode == USB_DR_MODE_HOST) 198687d66f28SThierry Reding value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(index); 1987ac25b6e9SNagarjuna Kristam else if (port->mode == USB_DR_MODE_OTG) 1988ac25b6e9SNagarjuna Kristam value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_OTG(index); 198987d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP); 199087d66f28SThierry Reding 199187d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); 199287d66f28SThierry Reding value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK << 199387d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT) | 199487d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD | 199587d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 | 199687d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI); 199787d66f28SThierry Reding value |= (priv->fuse.hs_curr_level[index] + 199887d66f28SThierry Reding usb2->hs_curr_level_offset) << 199987d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT; 200087d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); 200187d66f28SThierry Reding 200287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); 200387d66f28SThierry Reding value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK << 200487d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) | 200587d66f28SThierry Reding (XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_MASK << 200687d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT) | 200787d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR | 200887d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD | 200987d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD); 201087d66f28SThierry Reding value |= (priv->fuse.hs_term_range_adj << 201187d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) | 201287d66f28SThierry Reding (priv->fuse.rpd_ctrl << 201387d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT); 201487d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); 201587d66f28SThierry Reding 201687d66f28SThierry Reding value = padctl_readl(padctl, 201787d66f28SThierry Reding XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index)); 201887d66f28SThierry Reding value &= ~(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_MASK << 201987d66f28SThierry Reding XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT); 2020ac25b6e9SNagarjuna Kristam if (port->mode == USB_DR_MODE_HOST) 202187d66f28SThierry Reding value |= XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18; 2022ac25b6e9SNagarjuna Kristam else 2023ac25b6e9SNagarjuna Kristam value |= 2024ac25b6e9SNagarjuna Kristam XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_VAL << 2025ac25b6e9SNagarjuna Kristam XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT; 202687d66f28SThierry Reding padctl_writel(padctl, value, 202787d66f28SThierry Reding XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index)); 202887d66f28SThierry Reding 2029de792a6dSNagarjuna Kristam if (port->supply && port->mode == USB_DR_MODE_HOST) { 203087d66f28SThierry Reding err = regulator_enable(port->supply); 203187d66f28SThierry Reding if (err) 203287d66f28SThierry Reding return err; 2033de792a6dSNagarjuna Kristam } 203487d66f28SThierry Reding 203587d66f28SThierry Reding mutex_lock(&padctl->lock); 203687d66f28SThierry Reding 203787d66f28SThierry Reding if (pad->enable > 0) { 203887d66f28SThierry Reding pad->enable++; 203987d66f28SThierry Reding mutex_unlock(&padctl->lock); 204087d66f28SThierry Reding return 0; 204187d66f28SThierry Reding } 204287d66f28SThierry Reding 204387d66f28SThierry Reding err = clk_prepare_enable(pad->clk); 204487d66f28SThierry Reding if (err) 204587d66f28SThierry Reding goto disable_regulator; 204687d66f28SThierry Reding 204787d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 204887d66f28SThierry Reding value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK << 204987d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) | 205087d66f28SThierry Reding (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_MASK << 205187d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT)); 205287d66f28SThierry Reding value |= (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL << 205387d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) | 205487d66f28SThierry Reding (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_VAL << 205587d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT); 205687d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 205787d66f28SThierry Reding 205887d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 205987d66f28SThierry Reding value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; 206087d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 206187d66f28SThierry Reding 206287d66f28SThierry Reding udelay(1); 206387d66f28SThierry Reding 206487d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 206587d66f28SThierry Reding value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL1_PD_TRK; 206687d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 206787d66f28SThierry Reding 206887d66f28SThierry Reding udelay(50); 206987d66f28SThierry Reding 207087d66f28SThierry Reding clk_disable_unprepare(pad->clk); 207187d66f28SThierry Reding 207287d66f28SThierry Reding pad->enable++; 207387d66f28SThierry Reding mutex_unlock(&padctl->lock); 207487d66f28SThierry Reding 207587d66f28SThierry Reding return 0; 207687d66f28SThierry Reding 207787d66f28SThierry Reding disable_regulator: 207887d66f28SThierry Reding regulator_disable(port->supply); 207987d66f28SThierry Reding mutex_unlock(&padctl->lock); 208087d66f28SThierry Reding return err; 208187d66f28SThierry Reding } 208287d66f28SThierry Reding 208387d66f28SThierry Reding static int tegra210_usb2_phy_power_off(struct phy *phy) 208487d66f28SThierry Reding { 208587d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 208687d66f28SThierry Reding struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad); 208787d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 208887d66f28SThierry Reding struct tegra_xusb_usb2_port *port; 208987d66f28SThierry Reding u32 value; 209087d66f28SThierry Reding 209187d66f28SThierry Reding port = tegra_xusb_find_usb2_port(padctl, lane->index); 209287d66f28SThierry Reding if (!port) { 209387d66f28SThierry Reding dev_err(&phy->dev, "no port found for USB2 lane %u\n", 209487d66f28SThierry Reding lane->index); 209587d66f28SThierry Reding return -ENODEV; 209687d66f28SThierry Reding } 209787d66f28SThierry Reding 209887d66f28SThierry Reding mutex_lock(&padctl->lock); 209987d66f28SThierry Reding 2100a5be28c3SNagarjuna Kristam if (port->usb3_port_fake != -1) { 2101a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 2102a5be28c3SNagarjuna Kristam value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY( 2103a5be28c3SNagarjuna Kristam port->usb3_port_fake); 2104a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 2105a5be28c3SNagarjuna Kristam 2106a5be28c3SNagarjuna Kristam usleep_range(100, 200); 2107a5be28c3SNagarjuna Kristam 2108a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 2109a5be28c3SNagarjuna Kristam value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN( 2110a5be28c3SNagarjuna Kristam port->usb3_port_fake); 2111a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 2112a5be28c3SNagarjuna Kristam 2113a5be28c3SNagarjuna Kristam usleep_range(250, 350); 2114a5be28c3SNagarjuna Kristam 2115a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 2116a5be28c3SNagarjuna Kristam value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN( 2117a5be28c3SNagarjuna Kristam port->usb3_port_fake); 2118a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 2119a5be28c3SNagarjuna Kristam 2120a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); 2121a5be28c3SNagarjuna Kristam value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(port->usb3_port_fake, 2122a5be28c3SNagarjuna Kristam XUSB_PADCTL_SS_PORT_MAP_PORT_DISABLED); 2123a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP); 2124a5be28c3SNagarjuna Kristam } 2125a5be28c3SNagarjuna Kristam 212687d66f28SThierry Reding if (WARN_ON(pad->enable == 0)) 212787d66f28SThierry Reding goto out; 212887d66f28SThierry Reding 212987d66f28SThierry Reding if (--pad->enable > 0) 213087d66f28SThierry Reding goto out; 213187d66f28SThierry Reding 213287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 213387d66f28SThierry Reding value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; 213487d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 213587d66f28SThierry Reding 213687d66f28SThierry Reding out: 213787d66f28SThierry Reding regulator_disable(port->supply); 213887d66f28SThierry Reding mutex_unlock(&padctl->lock); 213987d66f28SThierry Reding return 0; 214087d66f28SThierry Reding } 214187d66f28SThierry Reding 214287d66f28SThierry Reding static const struct phy_ops tegra210_usb2_phy_ops = { 214387d66f28SThierry Reding .init = tegra210_usb2_phy_init, 214487d66f28SThierry Reding .exit = tegra210_usb2_phy_exit, 214587d66f28SThierry Reding .power_on = tegra210_usb2_phy_power_on, 214687d66f28SThierry Reding .power_off = tegra210_usb2_phy_power_off, 2147de792a6dSNagarjuna Kristam .set_mode = tegra210_usb2_phy_set_mode, 214887d66f28SThierry Reding .owner = THIS_MODULE, 214987d66f28SThierry Reding }; 215087d66f28SThierry Reding 215187d66f28SThierry Reding static struct tegra_xusb_pad * 215287d66f28SThierry Reding tegra210_usb2_pad_probe(struct tegra_xusb_padctl *padctl, 215387d66f28SThierry Reding const struct tegra_xusb_pad_soc *soc, 215487d66f28SThierry Reding struct device_node *np) 215587d66f28SThierry Reding { 215687d66f28SThierry Reding struct tegra_xusb_usb2_pad *usb2; 215787d66f28SThierry Reding struct tegra_xusb_pad *pad; 215887d66f28SThierry Reding int err; 215987d66f28SThierry Reding 216087d66f28SThierry Reding usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL); 216187d66f28SThierry Reding if (!usb2) 216287d66f28SThierry Reding return ERR_PTR(-ENOMEM); 216387d66f28SThierry Reding 216487d66f28SThierry Reding pad = &usb2->base; 216587d66f28SThierry Reding pad->ops = &tegra210_usb2_lane_ops; 216687d66f28SThierry Reding pad->soc = soc; 216787d66f28SThierry Reding 216887d66f28SThierry Reding err = tegra_xusb_pad_init(pad, padctl, np); 216987d66f28SThierry Reding if (err < 0) { 217087d66f28SThierry Reding kfree(usb2); 217187d66f28SThierry Reding goto out; 217287d66f28SThierry Reding } 217387d66f28SThierry Reding 217487d66f28SThierry Reding usb2->clk = devm_clk_get(&pad->dev, "trk"); 217587d66f28SThierry Reding if (IS_ERR(usb2->clk)) { 217687d66f28SThierry Reding err = PTR_ERR(usb2->clk); 217787d66f28SThierry Reding dev_err(&pad->dev, "failed to get trk clock: %d\n", err); 217887d66f28SThierry Reding goto unregister; 217987d66f28SThierry Reding } 218087d66f28SThierry Reding 218187d66f28SThierry Reding err = tegra_xusb_pad_register(pad, &tegra210_usb2_phy_ops); 218287d66f28SThierry Reding if (err < 0) 218387d66f28SThierry Reding goto unregister; 218487d66f28SThierry Reding 218587d66f28SThierry Reding dev_set_drvdata(&pad->dev, pad); 218687d66f28SThierry Reding 218787d66f28SThierry Reding return pad; 218887d66f28SThierry Reding 218987d66f28SThierry Reding unregister: 219087d66f28SThierry Reding device_unregister(&pad->dev); 219187d66f28SThierry Reding out: 219287d66f28SThierry Reding return ERR_PTR(err); 219387d66f28SThierry Reding } 219487d66f28SThierry Reding 219587d66f28SThierry Reding static void tegra210_usb2_pad_remove(struct tegra_xusb_pad *pad) 219687d66f28SThierry Reding { 219787d66f28SThierry Reding struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad); 219887d66f28SThierry Reding 219987d66f28SThierry Reding kfree(usb2); 220087d66f28SThierry Reding } 220187d66f28SThierry Reding 220287d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_usb2_ops = { 220387d66f28SThierry Reding .probe = tegra210_usb2_pad_probe, 220487d66f28SThierry Reding .remove = tegra210_usb2_pad_remove, 220587d66f28SThierry Reding }; 220687d66f28SThierry Reding 220787d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_usb2_pad = { 220887d66f28SThierry Reding .name = "usb2", 220987d66f28SThierry Reding .num_lanes = ARRAY_SIZE(tegra210_usb2_lanes), 221087d66f28SThierry Reding .lanes = tegra210_usb2_lanes, 221187d66f28SThierry Reding .ops = &tegra210_usb2_ops, 221287d66f28SThierry Reding }; 221387d66f28SThierry Reding 221487d66f28SThierry Reding static const char *tegra210_hsic_functions[] = { 221587d66f28SThierry Reding "snps", 221687d66f28SThierry Reding "xusb", 221787d66f28SThierry Reding }; 221887d66f28SThierry Reding 221987d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_hsic_lanes[] = { 222087d66f28SThierry Reding TEGRA210_LANE("hsic-0", 0x004, 14, 0x1, hsic), 222187d66f28SThierry Reding }; 222287d66f28SThierry Reding 222387d66f28SThierry Reding static struct tegra_xusb_lane * 222487d66f28SThierry Reding tegra210_hsic_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, 222587d66f28SThierry Reding unsigned int index) 222687d66f28SThierry Reding { 222787d66f28SThierry Reding struct tegra_xusb_hsic_lane *hsic; 222887d66f28SThierry Reding int err; 222987d66f28SThierry Reding 223087d66f28SThierry Reding hsic = kzalloc(sizeof(*hsic), GFP_KERNEL); 223187d66f28SThierry Reding if (!hsic) 223287d66f28SThierry Reding return ERR_PTR(-ENOMEM); 223387d66f28SThierry Reding 223487d66f28SThierry Reding INIT_LIST_HEAD(&hsic->base.list); 223587d66f28SThierry Reding hsic->base.soc = &pad->soc->lanes[index]; 223687d66f28SThierry Reding hsic->base.index = index; 223787d66f28SThierry Reding hsic->base.pad = pad; 223887d66f28SThierry Reding hsic->base.np = np; 223987d66f28SThierry Reding 224087d66f28SThierry Reding err = tegra_xusb_lane_parse_dt(&hsic->base, np); 224187d66f28SThierry Reding if (err < 0) { 224287d66f28SThierry Reding kfree(hsic); 224387d66f28SThierry Reding return ERR_PTR(err); 224487d66f28SThierry Reding } 224587d66f28SThierry Reding 224687d66f28SThierry Reding return &hsic->base; 224787d66f28SThierry Reding } 224887d66f28SThierry Reding 224987d66f28SThierry Reding static void tegra210_hsic_lane_remove(struct tegra_xusb_lane *lane) 225087d66f28SThierry Reding { 225187d66f28SThierry Reding struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane); 225287d66f28SThierry Reding 225387d66f28SThierry Reding kfree(hsic); 225487d66f28SThierry Reding } 225587d66f28SThierry Reding 225687d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_hsic_lane_ops = { 225787d66f28SThierry Reding .probe = tegra210_hsic_lane_probe, 225887d66f28SThierry Reding .remove = tegra210_hsic_lane_remove, 2259*2d102148SJC Kuo .enable_phy_sleepwalk = tegra210_pmc_hsic_enable_phy_sleepwalk, 2260*2d102148SJC Kuo .disable_phy_sleepwalk = tegra210_pmc_hsic_disable_phy_sleepwalk, 2261*2d102148SJC Kuo .enable_phy_wake = tegra210_hsic_enable_phy_wake, 2262*2d102148SJC Kuo .disable_phy_wake = tegra210_hsic_disable_phy_wake, 2263*2d102148SJC Kuo .remote_wake_detected = tegra210_hsic_phy_remote_wake_detected, 226487d66f28SThierry Reding }; 226587d66f28SThierry Reding 226687d66f28SThierry Reding static int tegra210_hsic_phy_init(struct phy *phy) 226787d66f28SThierry Reding { 226887d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 226987d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 227087d66f28SThierry Reding u32 value; 227187d66f28SThierry Reding 227287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX); 227387d66f28SThierry Reding value &= ~(XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_MASK << 227487d66f28SThierry Reding XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT); 227587d66f28SThierry Reding value |= XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_XUSB << 227687d66f28SThierry Reding XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT; 227787d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX); 227887d66f28SThierry Reding 22792352fdb0SJC Kuo return 0; 228087d66f28SThierry Reding } 228187d66f28SThierry Reding 228287d66f28SThierry Reding static int tegra210_hsic_phy_exit(struct phy *phy) 228387d66f28SThierry Reding { 22842352fdb0SJC Kuo return 0; 228587d66f28SThierry Reding } 228687d66f28SThierry Reding 228787d66f28SThierry Reding static int tegra210_hsic_phy_power_on(struct phy *phy) 228887d66f28SThierry Reding { 228987d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 229087d66f28SThierry Reding struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane); 229187d66f28SThierry Reding struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad); 229287d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 229387d66f28SThierry Reding unsigned int index = lane->index; 229487d66f28SThierry Reding u32 value; 229587d66f28SThierry Reding int err; 229687d66f28SThierry Reding 229787d66f28SThierry Reding err = regulator_enable(pad->supply); 229887d66f28SThierry Reding if (err) 229987d66f28SThierry Reding return err; 230087d66f28SThierry Reding 230187d66f28SThierry Reding padctl_writel(padctl, hsic->strobe_trim, 230287d66f28SThierry Reding XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL); 230387d66f28SThierry Reding 230487d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index)); 230587d66f28SThierry Reding value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_MASK << 230687d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT); 230787d66f28SThierry Reding value |= (hsic->tx_rtune_p << 230887d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT); 230987d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index)); 231087d66f28SThierry Reding 231187d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(index)); 231287d66f28SThierry Reding value &= ~((XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK << 231387d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) | 231487d66f28SThierry Reding (XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK << 231587d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT)); 231687d66f28SThierry Reding value |= (hsic->rx_strobe_trim << 231787d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) | 231887d66f28SThierry Reding (hsic->rx_data_trim << 231987d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT); 232087d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL2(index)); 232187d66f28SThierry Reding 232287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index)); 232387d66f28SThierry Reding value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 | 232487d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 | 232587d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE | 232687d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 | 232787d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 | 232887d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE | 232987d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 | 233087d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 | 233187d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE | 233287d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 | 233387d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 | 233487d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE); 233587d66f28SThierry Reding value |= XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 | 233687d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 | 233787d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE; 233887d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL0(index)); 233987d66f28SThierry Reding 234087d66f28SThierry Reding err = clk_prepare_enable(pad->clk); 234187d66f28SThierry Reding if (err) 234287d66f28SThierry Reding goto disable; 234387d66f28SThierry Reding 234487d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PAD_TRK_CTL); 234587d66f28SThierry Reding value &= ~((XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_MASK << 234687d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT) | 234787d66f28SThierry Reding (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_MASK << 234887d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT)); 234987d66f28SThierry Reding value |= (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_VAL << 235087d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT) | 235187d66f28SThierry Reding (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_VAL << 235287d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT); 235387d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PAD_TRK_CTL); 235487d66f28SThierry Reding 235587d66f28SThierry Reding udelay(1); 235687d66f28SThierry Reding 235787d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PAD_TRK_CTL); 235887d66f28SThierry Reding value &= ~XUSB_PADCTL_HSIC_PAD_TRK_CTL_PD_TRK; 235987d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PAD_TRK_CTL); 236087d66f28SThierry Reding 236187d66f28SThierry Reding udelay(50); 236287d66f28SThierry Reding 236387d66f28SThierry Reding clk_disable_unprepare(pad->clk); 236487d66f28SThierry Reding 236587d66f28SThierry Reding return 0; 236687d66f28SThierry Reding 236787d66f28SThierry Reding disable: 236887d66f28SThierry Reding regulator_disable(pad->supply); 236987d66f28SThierry Reding return err; 237087d66f28SThierry Reding } 237187d66f28SThierry Reding 237287d66f28SThierry Reding static int tegra210_hsic_phy_power_off(struct phy *phy) 237387d66f28SThierry Reding { 237487d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 237587d66f28SThierry Reding struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad); 237687d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 237787d66f28SThierry Reding unsigned int index = lane->index; 237887d66f28SThierry Reding u32 value; 237987d66f28SThierry Reding 238087d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index)); 238187d66f28SThierry Reding value |= XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 | 238287d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 | 238387d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE | 238487d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 | 238587d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 | 238687d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE | 238787d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 | 238887d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 | 238987d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE; 239087d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index)); 239187d66f28SThierry Reding 239287d66f28SThierry Reding regulator_disable(pad->supply); 239387d66f28SThierry Reding 239487d66f28SThierry Reding return 0; 239587d66f28SThierry Reding } 239687d66f28SThierry Reding 239787d66f28SThierry Reding static const struct phy_ops tegra210_hsic_phy_ops = { 239887d66f28SThierry Reding .init = tegra210_hsic_phy_init, 239987d66f28SThierry Reding .exit = tegra210_hsic_phy_exit, 240087d66f28SThierry Reding .power_on = tegra210_hsic_phy_power_on, 240187d66f28SThierry Reding .power_off = tegra210_hsic_phy_power_off, 240287d66f28SThierry Reding .owner = THIS_MODULE, 240387d66f28SThierry Reding }; 240487d66f28SThierry Reding 240587d66f28SThierry Reding static struct tegra_xusb_pad * 240687d66f28SThierry Reding tegra210_hsic_pad_probe(struct tegra_xusb_padctl *padctl, 240787d66f28SThierry Reding const struct tegra_xusb_pad_soc *soc, 240887d66f28SThierry Reding struct device_node *np) 240987d66f28SThierry Reding { 241087d66f28SThierry Reding struct tegra_xusb_hsic_pad *hsic; 241187d66f28SThierry Reding struct tegra_xusb_pad *pad; 241287d66f28SThierry Reding int err; 241387d66f28SThierry Reding 241487d66f28SThierry Reding hsic = kzalloc(sizeof(*hsic), GFP_KERNEL); 241587d66f28SThierry Reding if (!hsic) 241687d66f28SThierry Reding return ERR_PTR(-ENOMEM); 241787d66f28SThierry Reding 241887d66f28SThierry Reding pad = &hsic->base; 241987d66f28SThierry Reding pad->ops = &tegra210_hsic_lane_ops; 242087d66f28SThierry Reding pad->soc = soc; 242187d66f28SThierry Reding 242287d66f28SThierry Reding err = tegra_xusb_pad_init(pad, padctl, np); 242387d66f28SThierry Reding if (err < 0) { 242487d66f28SThierry Reding kfree(hsic); 242587d66f28SThierry Reding goto out; 242687d66f28SThierry Reding } 242787d66f28SThierry Reding 242887d66f28SThierry Reding hsic->clk = devm_clk_get(&pad->dev, "trk"); 242987d66f28SThierry Reding if (IS_ERR(hsic->clk)) { 243087d66f28SThierry Reding err = PTR_ERR(hsic->clk); 243187d66f28SThierry Reding dev_err(&pad->dev, "failed to get trk clock: %d\n", err); 243287d66f28SThierry Reding goto unregister; 243387d66f28SThierry Reding } 243487d66f28SThierry Reding 243587d66f28SThierry Reding err = tegra_xusb_pad_register(pad, &tegra210_hsic_phy_ops); 243687d66f28SThierry Reding if (err < 0) 243787d66f28SThierry Reding goto unregister; 243887d66f28SThierry Reding 243987d66f28SThierry Reding dev_set_drvdata(&pad->dev, pad); 244087d66f28SThierry Reding 244187d66f28SThierry Reding return pad; 244287d66f28SThierry Reding 244387d66f28SThierry Reding unregister: 244487d66f28SThierry Reding device_unregister(&pad->dev); 244587d66f28SThierry Reding out: 244687d66f28SThierry Reding return ERR_PTR(err); 244787d66f28SThierry Reding } 244887d66f28SThierry Reding 244987d66f28SThierry Reding static void tegra210_hsic_pad_remove(struct tegra_xusb_pad *pad) 245087d66f28SThierry Reding { 245187d66f28SThierry Reding struct tegra_xusb_hsic_pad *hsic = to_hsic_pad(pad); 245287d66f28SThierry Reding 245387d66f28SThierry Reding kfree(hsic); 245487d66f28SThierry Reding } 245587d66f28SThierry Reding 245687d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_hsic_ops = { 245787d66f28SThierry Reding .probe = tegra210_hsic_pad_probe, 245887d66f28SThierry Reding .remove = tegra210_hsic_pad_remove, 245987d66f28SThierry Reding }; 246087d66f28SThierry Reding 246187d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_hsic_pad = { 246287d66f28SThierry Reding .name = "hsic", 246387d66f28SThierry Reding .num_lanes = ARRAY_SIZE(tegra210_hsic_lanes), 246487d66f28SThierry Reding .lanes = tegra210_hsic_lanes, 246587d66f28SThierry Reding .ops = &tegra210_hsic_ops, 246687d66f28SThierry Reding }; 246787d66f28SThierry Reding 2468c339605cSJC Kuo static void tegra210_uphy_lane_iddq_enable(struct tegra_xusb_lane *lane) 2469c339605cSJC Kuo { 2470c339605cSJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 2471c339605cSJC Kuo u32 value; 2472c339605cSJC Kuo 2473c339605cSJC Kuo value = padctl_readl(padctl, lane->soc->regs.misc_ctl2); 2474c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD; 2475c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD; 2476c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD; 2477c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD; 2478c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ; 2479c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK; 2480c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL; 2481c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ; 2482c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK; 2483c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL; 2484c339605cSJC Kuo padctl_writel(padctl, value, lane->soc->regs.misc_ctl2); 2485c339605cSJC Kuo } 2486c339605cSJC Kuo 2487c339605cSJC Kuo static void tegra210_uphy_lane_iddq_disable(struct tegra_xusb_lane *lane) 2488c339605cSJC Kuo { 2489c339605cSJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 2490c339605cSJC Kuo u32 value; 2491c339605cSJC Kuo 2492c339605cSJC Kuo value = padctl_readl(padctl, lane->soc->regs.misc_ctl2); 2493c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD; 2494c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD; 2495c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD; 2496c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD; 2497c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ; 2498c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK; 2499c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL; 2500c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ; 2501c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK; 2502c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL; 2503c339605cSJC Kuo padctl_writel(padctl, value, lane->soc->regs.misc_ctl2); 2504c339605cSJC Kuo } 2505c339605cSJC Kuo 2506c339605cSJC Kuo #define TEGRA210_UPHY_LANE(_name, _offset, _shift, _mask, _type, _misc) \ 2507c339605cSJC Kuo { \ 2508c339605cSJC Kuo .name = _name, \ 2509c339605cSJC Kuo .offset = _offset, \ 2510c339605cSJC Kuo .shift = _shift, \ 2511c339605cSJC Kuo .mask = _mask, \ 2512c339605cSJC Kuo .num_funcs = ARRAY_SIZE(tegra210_##_type##_functions), \ 2513c339605cSJC Kuo .funcs = tegra210_##_type##_functions, \ 2514c339605cSJC Kuo .regs.misc_ctl2 = _misc, \ 2515c339605cSJC Kuo } 2516c339605cSJC Kuo 251787d66f28SThierry Reding static const char *tegra210_pcie_functions[] = { 251887d66f28SThierry Reding "pcie-x1", 251987d66f28SThierry Reding "usb3-ss", 252087d66f28SThierry Reding "sata", 252187d66f28SThierry Reding "pcie-x4", 252287d66f28SThierry Reding }; 252387d66f28SThierry Reding 252487d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_pcie_lanes[] = { 2525c339605cSJC Kuo TEGRA210_UPHY_LANE("pcie-0", 0x028, 12, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)), 2526c339605cSJC Kuo TEGRA210_UPHY_LANE("pcie-1", 0x028, 14, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(1)), 2527c339605cSJC Kuo TEGRA210_UPHY_LANE("pcie-2", 0x028, 16, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(2)), 2528c339605cSJC Kuo TEGRA210_UPHY_LANE("pcie-3", 0x028, 18, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(3)), 2529c339605cSJC Kuo TEGRA210_UPHY_LANE("pcie-4", 0x028, 20, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(4)), 2530c339605cSJC Kuo TEGRA210_UPHY_LANE("pcie-5", 0x028, 22, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(5)), 2531c339605cSJC Kuo TEGRA210_UPHY_LANE("pcie-6", 0x028, 24, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(6)), 253287d66f28SThierry Reding }; 253387d66f28SThierry Reding 253423d5ec3fSJC Kuo static struct tegra_xusb_usb3_port * 253523d5ec3fSJC Kuo tegra210_lane_to_usb3_port(struct tegra_xusb_lane *lane) 253623d5ec3fSJC Kuo { 253723d5ec3fSJC Kuo int port; 253823d5ec3fSJC Kuo 253923d5ec3fSJC Kuo if (!lane || !lane->pad || !lane->pad->padctl) 254023d5ec3fSJC Kuo return NULL; 254123d5ec3fSJC Kuo 254223d5ec3fSJC Kuo port = tegra210_usb3_lane_map(lane); 254323d5ec3fSJC Kuo if (port < 0) 254423d5ec3fSJC Kuo return NULL; 254523d5ec3fSJC Kuo 254623d5ec3fSJC Kuo return tegra_xusb_find_usb3_port(lane->pad->padctl, port); 254723d5ec3fSJC Kuo } 254823d5ec3fSJC Kuo 254923d5ec3fSJC Kuo static int tegra210_usb3_phy_power_on(struct phy *phy) 255023d5ec3fSJC Kuo { 255123d5ec3fSJC Kuo struct device *dev = &phy->dev; 255223d5ec3fSJC Kuo struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 255323d5ec3fSJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 255423d5ec3fSJC Kuo struct tegra_xusb_usb3_port *usb3 = tegra210_lane_to_usb3_port(lane); 255523d5ec3fSJC Kuo unsigned int index; 255623d5ec3fSJC Kuo u32 value; 255723d5ec3fSJC Kuo 255823d5ec3fSJC Kuo if (!usb3) { 255923d5ec3fSJC Kuo dev_err(dev, "no USB3 port found for lane %u\n", lane->index); 256023d5ec3fSJC Kuo return -ENODEV; 256123d5ec3fSJC Kuo } 256223d5ec3fSJC Kuo 256323d5ec3fSJC Kuo index = usb3->base.index; 256423d5ec3fSJC Kuo 256523d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); 256623d5ec3fSJC Kuo 256723d5ec3fSJC Kuo if (!usb3->internal) 256823d5ec3fSJC Kuo value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index); 256923d5ec3fSJC Kuo else 257023d5ec3fSJC Kuo value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index); 257123d5ec3fSJC Kuo 257223d5ec3fSJC Kuo value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(index); 257323d5ec3fSJC Kuo value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(index, usb3->port); 257423d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP); 257523d5ec3fSJC Kuo 257623d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index)); 257723d5ec3fSJC Kuo value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_MASK << 257823d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT); 257923d5ec3fSJC Kuo value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_VAL << 258023d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT; 258123d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index)); 258223d5ec3fSJC Kuo 258323d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index)); 258423d5ec3fSJC Kuo value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_MASK << 258523d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT); 258623d5ec3fSJC Kuo value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_VAL << 258723d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT; 258823d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index)); 258923d5ec3fSJC Kuo 259023d5ec3fSJC Kuo padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL3_RX_DFE_VAL, 259123d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PADX_ECTL3(index)); 259223d5ec3fSJC Kuo 259323d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index)); 259423d5ec3fSJC Kuo value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_MASK << 259523d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT); 259623d5ec3fSJC Kuo value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_VAL << 259723d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT; 259823d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index)); 259923d5ec3fSJC Kuo 260023d5ec3fSJC Kuo padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL6_RX_EQ_CTRL_H_VAL, 260123d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PADX_ECTL6(index)); 260223d5ec3fSJC Kuo 260323d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 260423d5ec3fSJC Kuo value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index); 260523d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 260623d5ec3fSJC Kuo 260723d5ec3fSJC Kuo usleep_range(100, 200); 260823d5ec3fSJC Kuo 260923d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 261023d5ec3fSJC Kuo value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index); 261123d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 261223d5ec3fSJC Kuo 261323d5ec3fSJC Kuo usleep_range(100, 200); 261423d5ec3fSJC Kuo 261523d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 261623d5ec3fSJC Kuo value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index); 261723d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 261823d5ec3fSJC Kuo 261923d5ec3fSJC Kuo return 0; 262023d5ec3fSJC Kuo } 262123d5ec3fSJC Kuo 262223d5ec3fSJC Kuo static int tegra210_usb3_phy_power_off(struct phy *phy) 262323d5ec3fSJC Kuo { 262423d5ec3fSJC Kuo struct device *dev = &phy->dev; 262523d5ec3fSJC Kuo struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 262623d5ec3fSJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 262723d5ec3fSJC Kuo struct tegra_xusb_usb3_port *usb3 = tegra210_lane_to_usb3_port(lane); 262823d5ec3fSJC Kuo unsigned int index; 262923d5ec3fSJC Kuo u32 value; 263023d5ec3fSJC Kuo 263123d5ec3fSJC Kuo if (!usb3) { 263223d5ec3fSJC Kuo dev_err(dev, "no USB3 port found for lane %u\n", lane->index); 263323d5ec3fSJC Kuo return -ENODEV; 263423d5ec3fSJC Kuo } 263523d5ec3fSJC Kuo 263623d5ec3fSJC Kuo index = usb3->base.index; 263723d5ec3fSJC Kuo 263823d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 263923d5ec3fSJC Kuo value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index); 264023d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 264123d5ec3fSJC Kuo 264223d5ec3fSJC Kuo usleep_range(100, 200); 264323d5ec3fSJC Kuo 264423d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 264523d5ec3fSJC Kuo value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index); 264623d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 264723d5ec3fSJC Kuo 264823d5ec3fSJC Kuo usleep_range(250, 350); 264923d5ec3fSJC Kuo 265023d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 265123d5ec3fSJC Kuo value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index); 265223d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 265323d5ec3fSJC Kuo 265423d5ec3fSJC Kuo return 0; 265523d5ec3fSJC Kuo } 265687d66f28SThierry Reding static struct tegra_xusb_lane * 265787d66f28SThierry Reding tegra210_pcie_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, 265887d66f28SThierry Reding unsigned int index) 265987d66f28SThierry Reding { 266087d66f28SThierry Reding struct tegra_xusb_pcie_lane *pcie; 266187d66f28SThierry Reding int err; 266287d66f28SThierry Reding 266387d66f28SThierry Reding pcie = kzalloc(sizeof(*pcie), GFP_KERNEL); 266487d66f28SThierry Reding if (!pcie) 266587d66f28SThierry Reding return ERR_PTR(-ENOMEM); 266687d66f28SThierry Reding 266787d66f28SThierry Reding INIT_LIST_HEAD(&pcie->base.list); 266887d66f28SThierry Reding pcie->base.soc = &pad->soc->lanes[index]; 266987d66f28SThierry Reding pcie->base.index = index; 267087d66f28SThierry Reding pcie->base.pad = pad; 267187d66f28SThierry Reding pcie->base.np = np; 267287d66f28SThierry Reding 267387d66f28SThierry Reding err = tegra_xusb_lane_parse_dt(&pcie->base, np); 267487d66f28SThierry Reding if (err < 0) { 267587d66f28SThierry Reding kfree(pcie); 267687d66f28SThierry Reding return ERR_PTR(err); 267787d66f28SThierry Reding } 267887d66f28SThierry Reding 267987d66f28SThierry Reding return &pcie->base; 268087d66f28SThierry Reding } 268187d66f28SThierry Reding 268287d66f28SThierry Reding static void tegra210_pcie_lane_remove(struct tegra_xusb_lane *lane) 268387d66f28SThierry Reding { 268487d66f28SThierry Reding struct tegra_xusb_pcie_lane *pcie = to_pcie_lane(lane); 268587d66f28SThierry Reding 268687d66f28SThierry Reding kfree(pcie); 268787d66f28SThierry Reding } 268887d66f28SThierry Reding 268987d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_pcie_lane_ops = { 269087d66f28SThierry Reding .probe = tegra210_pcie_lane_probe, 269187d66f28SThierry Reding .remove = tegra210_pcie_lane_remove, 2692c339605cSJC Kuo .iddq_enable = tegra210_uphy_lane_iddq_enable, 2693c339605cSJC Kuo .iddq_disable = tegra210_uphy_lane_iddq_disable, 2694*2d102148SJC Kuo .enable_phy_sleepwalk = tegra210_usb3_enable_phy_sleepwalk, 2695*2d102148SJC Kuo .disable_phy_sleepwalk = tegra210_usb3_disable_phy_sleepwalk, 2696*2d102148SJC Kuo .enable_phy_wake = tegra210_usb3_enable_phy_wake, 2697*2d102148SJC Kuo .disable_phy_wake = tegra210_usb3_disable_phy_wake, 2698*2d102148SJC Kuo .remote_wake_detected = tegra210_usb3_phy_remote_wake_detected, 269987d66f28SThierry Reding }; 270087d66f28SThierry Reding 270187d66f28SThierry Reding static int tegra210_pcie_phy_init(struct phy *phy) 270287d66f28SThierry Reding { 270387d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 27042352fdb0SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 270587d66f28SThierry Reding 27062352fdb0SJC Kuo mutex_lock(&padctl->lock); 270787d66f28SThierry Reding 27082352fdb0SJC Kuo tegra210_uphy_init(padctl); 270987d66f28SThierry Reding 27102352fdb0SJC Kuo mutex_unlock(&padctl->lock); 27112352fdb0SJC Kuo 27122352fdb0SJC Kuo return 0; 271387d66f28SThierry Reding } 271487d66f28SThierry Reding 271587d66f28SThierry Reding static int tegra210_pcie_phy_power_on(struct phy *phy) 271687d66f28SThierry Reding { 271787d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 271887d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 27192352fdb0SJC Kuo int err = 0; 272087d66f28SThierry Reding 272187d66f28SThierry Reding mutex_lock(&padctl->lock); 272287d66f28SThierry Reding 272323d5ec3fSJC Kuo if (tegra_xusb_lane_check(lane, "usb3-ss")) 272423d5ec3fSJC Kuo err = tegra210_usb3_phy_power_on(phy); 272523d5ec3fSJC Kuo 272687d66f28SThierry Reding mutex_unlock(&padctl->lock); 272787d66f28SThierry Reding return err; 272887d66f28SThierry Reding } 272987d66f28SThierry Reding 273087d66f28SThierry Reding static int tegra210_pcie_phy_power_off(struct phy *phy) 273187d66f28SThierry Reding { 273287d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 273387d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 273423d5ec3fSJC Kuo int err = 0; 273587d66f28SThierry Reding 273623d5ec3fSJC Kuo mutex_lock(&padctl->lock); 273723d5ec3fSJC Kuo 273823d5ec3fSJC Kuo if (tegra_xusb_lane_check(lane, "usb3-ss")) 273923d5ec3fSJC Kuo err = tegra210_usb3_phy_power_off(phy); 274023d5ec3fSJC Kuo 274123d5ec3fSJC Kuo mutex_unlock(&padctl->lock); 274223d5ec3fSJC Kuo return err; 274387d66f28SThierry Reding } 274487d66f28SThierry Reding 274587d66f28SThierry Reding static const struct phy_ops tegra210_pcie_phy_ops = { 274687d66f28SThierry Reding .init = tegra210_pcie_phy_init, 274787d66f28SThierry Reding .power_on = tegra210_pcie_phy_power_on, 274887d66f28SThierry Reding .power_off = tegra210_pcie_phy_power_off, 274987d66f28SThierry Reding .owner = THIS_MODULE, 275087d66f28SThierry Reding }; 275187d66f28SThierry Reding 275287d66f28SThierry Reding static struct tegra_xusb_pad * 275387d66f28SThierry Reding tegra210_pcie_pad_probe(struct tegra_xusb_padctl *padctl, 275487d66f28SThierry Reding const struct tegra_xusb_pad_soc *soc, 275587d66f28SThierry Reding struct device_node *np) 275687d66f28SThierry Reding { 275787d66f28SThierry Reding struct tegra_xusb_pcie_pad *pcie; 275887d66f28SThierry Reding struct tegra_xusb_pad *pad; 275987d66f28SThierry Reding int err; 276087d66f28SThierry Reding 276187d66f28SThierry Reding pcie = kzalloc(sizeof(*pcie), GFP_KERNEL); 276287d66f28SThierry Reding if (!pcie) 276387d66f28SThierry Reding return ERR_PTR(-ENOMEM); 276487d66f28SThierry Reding 276587d66f28SThierry Reding pad = &pcie->base; 276687d66f28SThierry Reding pad->ops = &tegra210_pcie_lane_ops; 276787d66f28SThierry Reding pad->soc = soc; 276887d66f28SThierry Reding 276987d66f28SThierry Reding err = tegra_xusb_pad_init(pad, padctl, np); 277087d66f28SThierry Reding if (err < 0) { 277187d66f28SThierry Reding kfree(pcie); 277287d66f28SThierry Reding goto out; 277387d66f28SThierry Reding } 277487d66f28SThierry Reding 277587d66f28SThierry Reding pcie->pll = devm_clk_get(&pad->dev, "pll"); 277687d66f28SThierry Reding if (IS_ERR(pcie->pll)) { 277787d66f28SThierry Reding err = PTR_ERR(pcie->pll); 277887d66f28SThierry Reding dev_err(&pad->dev, "failed to get PLL: %d\n", err); 277987d66f28SThierry Reding goto unregister; 278087d66f28SThierry Reding } 278187d66f28SThierry Reding 278287d66f28SThierry Reding pcie->rst = devm_reset_control_get(&pad->dev, "phy"); 278387d66f28SThierry Reding if (IS_ERR(pcie->rst)) { 278487d66f28SThierry Reding err = PTR_ERR(pcie->rst); 278587d66f28SThierry Reding dev_err(&pad->dev, "failed to get PCIe pad reset: %d\n", err); 278687d66f28SThierry Reding goto unregister; 278787d66f28SThierry Reding } 278887d66f28SThierry Reding 278987d66f28SThierry Reding err = tegra_xusb_pad_register(pad, &tegra210_pcie_phy_ops); 279087d66f28SThierry Reding if (err < 0) 279187d66f28SThierry Reding goto unregister; 279287d66f28SThierry Reding 279387d66f28SThierry Reding dev_set_drvdata(&pad->dev, pad); 279487d66f28SThierry Reding 279587d66f28SThierry Reding return pad; 279687d66f28SThierry Reding 279787d66f28SThierry Reding unregister: 279887d66f28SThierry Reding device_unregister(&pad->dev); 279987d66f28SThierry Reding out: 280087d66f28SThierry Reding return ERR_PTR(err); 280187d66f28SThierry Reding } 280287d66f28SThierry Reding 280387d66f28SThierry Reding static void tegra210_pcie_pad_remove(struct tegra_xusb_pad *pad) 280487d66f28SThierry Reding { 280587d66f28SThierry Reding struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(pad); 280687d66f28SThierry Reding 280787d66f28SThierry Reding kfree(pcie); 280887d66f28SThierry Reding } 280987d66f28SThierry Reding 281087d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_pcie_ops = { 281187d66f28SThierry Reding .probe = tegra210_pcie_pad_probe, 281287d66f28SThierry Reding .remove = tegra210_pcie_pad_remove, 281387d66f28SThierry Reding }; 281487d66f28SThierry Reding 281587d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_pcie_pad = { 281687d66f28SThierry Reding .name = "pcie", 281787d66f28SThierry Reding .num_lanes = ARRAY_SIZE(tegra210_pcie_lanes), 281887d66f28SThierry Reding .lanes = tegra210_pcie_lanes, 281987d66f28SThierry Reding .ops = &tegra210_pcie_ops, 282087d66f28SThierry Reding }; 282187d66f28SThierry Reding 282287d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_sata_lanes[] = { 2823c339605cSJC Kuo TEGRA210_UPHY_LANE("sata-0", 0x028, 30, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2), 282487d66f28SThierry Reding }; 282587d66f28SThierry Reding 282687d66f28SThierry Reding static struct tegra_xusb_lane * 282787d66f28SThierry Reding tegra210_sata_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, 282887d66f28SThierry Reding unsigned int index) 282987d66f28SThierry Reding { 283087d66f28SThierry Reding struct tegra_xusb_sata_lane *sata; 283187d66f28SThierry Reding int err; 283287d66f28SThierry Reding 283387d66f28SThierry Reding sata = kzalloc(sizeof(*sata), GFP_KERNEL); 283487d66f28SThierry Reding if (!sata) 283587d66f28SThierry Reding return ERR_PTR(-ENOMEM); 283687d66f28SThierry Reding 283787d66f28SThierry Reding INIT_LIST_HEAD(&sata->base.list); 283887d66f28SThierry Reding sata->base.soc = &pad->soc->lanes[index]; 283987d66f28SThierry Reding sata->base.index = index; 284087d66f28SThierry Reding sata->base.pad = pad; 284187d66f28SThierry Reding sata->base.np = np; 284287d66f28SThierry Reding 284387d66f28SThierry Reding err = tegra_xusb_lane_parse_dt(&sata->base, np); 284487d66f28SThierry Reding if (err < 0) { 284587d66f28SThierry Reding kfree(sata); 284687d66f28SThierry Reding return ERR_PTR(err); 284787d66f28SThierry Reding } 284887d66f28SThierry Reding 284987d66f28SThierry Reding return &sata->base; 285087d66f28SThierry Reding } 285187d66f28SThierry Reding 285287d66f28SThierry Reding static void tegra210_sata_lane_remove(struct tegra_xusb_lane *lane) 285387d66f28SThierry Reding { 285487d66f28SThierry Reding struct tegra_xusb_sata_lane *sata = to_sata_lane(lane); 285587d66f28SThierry Reding 285687d66f28SThierry Reding kfree(sata); 285787d66f28SThierry Reding } 285887d66f28SThierry Reding 285987d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_sata_lane_ops = { 286087d66f28SThierry Reding .probe = tegra210_sata_lane_probe, 286187d66f28SThierry Reding .remove = tegra210_sata_lane_remove, 2862c339605cSJC Kuo .iddq_enable = tegra210_uphy_lane_iddq_enable, 2863c339605cSJC Kuo .iddq_disable = tegra210_uphy_lane_iddq_disable, 2864*2d102148SJC Kuo .enable_phy_sleepwalk = tegra210_usb3_enable_phy_sleepwalk, 2865*2d102148SJC Kuo .disable_phy_sleepwalk = tegra210_usb3_disable_phy_sleepwalk, 2866*2d102148SJC Kuo .enable_phy_wake = tegra210_usb3_enable_phy_wake, 2867*2d102148SJC Kuo .disable_phy_wake = tegra210_usb3_disable_phy_wake, 2868*2d102148SJC Kuo .remote_wake_detected = tegra210_usb3_phy_remote_wake_detected, 286987d66f28SThierry Reding }; 287087d66f28SThierry Reding 287187d66f28SThierry Reding static int tegra210_sata_phy_init(struct phy *phy) 287287d66f28SThierry Reding { 287387d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 28742352fdb0SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 287587d66f28SThierry Reding 28762352fdb0SJC Kuo mutex_lock(&padctl->lock); 287787d66f28SThierry Reding 28782352fdb0SJC Kuo tegra210_uphy_init(padctl); 287987d66f28SThierry Reding 28802352fdb0SJC Kuo mutex_unlock(&padctl->lock); 28812352fdb0SJC Kuo return 0; 288287d66f28SThierry Reding } 288387d66f28SThierry Reding 288487d66f28SThierry Reding static int tegra210_sata_phy_power_on(struct phy *phy) 288587d66f28SThierry Reding { 288687d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 288787d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 28882352fdb0SJC Kuo int err = 0; 288987d66f28SThierry Reding 289087d66f28SThierry Reding mutex_lock(&padctl->lock); 289187d66f28SThierry Reding 289223d5ec3fSJC Kuo if (tegra_xusb_lane_check(lane, "usb3-ss")) 289323d5ec3fSJC Kuo err = tegra210_usb3_phy_power_on(phy); 289423d5ec3fSJC Kuo 289587d66f28SThierry Reding mutex_unlock(&padctl->lock); 289687d66f28SThierry Reding return err; 289787d66f28SThierry Reding } 289887d66f28SThierry Reding 289987d66f28SThierry Reding static int tegra210_sata_phy_power_off(struct phy *phy) 290087d66f28SThierry Reding { 290187d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 290287d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 290323d5ec3fSJC Kuo int err = 0; 290487d66f28SThierry Reding 290523d5ec3fSJC Kuo mutex_lock(&padctl->lock); 290623d5ec3fSJC Kuo 290723d5ec3fSJC Kuo if (tegra_xusb_lane_check(lane, "usb3-ss")) 290823d5ec3fSJC Kuo err = tegra210_usb3_phy_power_off(phy); 290923d5ec3fSJC Kuo 291023d5ec3fSJC Kuo mutex_unlock(&padctl->lock); 291123d5ec3fSJC Kuo return err; 291287d66f28SThierry Reding } 291387d66f28SThierry Reding 291487d66f28SThierry Reding static const struct phy_ops tegra210_sata_phy_ops = { 291587d66f28SThierry Reding .init = tegra210_sata_phy_init, 291687d66f28SThierry Reding .power_on = tegra210_sata_phy_power_on, 291787d66f28SThierry Reding .power_off = tegra210_sata_phy_power_off, 291887d66f28SThierry Reding .owner = THIS_MODULE, 291987d66f28SThierry Reding }; 292087d66f28SThierry Reding 292187d66f28SThierry Reding static struct tegra_xusb_pad * 292287d66f28SThierry Reding tegra210_sata_pad_probe(struct tegra_xusb_padctl *padctl, 292387d66f28SThierry Reding const struct tegra_xusb_pad_soc *soc, 292487d66f28SThierry Reding struct device_node *np) 292587d66f28SThierry Reding { 292687d66f28SThierry Reding struct tegra_xusb_sata_pad *sata; 292787d66f28SThierry Reding struct tegra_xusb_pad *pad; 292887d66f28SThierry Reding int err; 292987d66f28SThierry Reding 293087d66f28SThierry Reding sata = kzalloc(sizeof(*sata), GFP_KERNEL); 293187d66f28SThierry Reding if (!sata) 293287d66f28SThierry Reding return ERR_PTR(-ENOMEM); 293387d66f28SThierry Reding 293487d66f28SThierry Reding pad = &sata->base; 293587d66f28SThierry Reding pad->ops = &tegra210_sata_lane_ops; 293687d66f28SThierry Reding pad->soc = soc; 293787d66f28SThierry Reding 293887d66f28SThierry Reding err = tegra_xusb_pad_init(pad, padctl, np); 293987d66f28SThierry Reding if (err < 0) { 294087d66f28SThierry Reding kfree(sata); 294187d66f28SThierry Reding goto out; 294287d66f28SThierry Reding } 294387d66f28SThierry Reding 294487d66f28SThierry Reding sata->rst = devm_reset_control_get(&pad->dev, "phy"); 294587d66f28SThierry Reding if (IS_ERR(sata->rst)) { 294687d66f28SThierry Reding err = PTR_ERR(sata->rst); 294787d66f28SThierry Reding dev_err(&pad->dev, "failed to get SATA pad reset: %d\n", err); 294887d66f28SThierry Reding goto unregister; 294987d66f28SThierry Reding } 295087d66f28SThierry Reding 295187d66f28SThierry Reding err = tegra_xusb_pad_register(pad, &tegra210_sata_phy_ops); 295287d66f28SThierry Reding if (err < 0) 295387d66f28SThierry Reding goto unregister; 295487d66f28SThierry Reding 295587d66f28SThierry Reding dev_set_drvdata(&pad->dev, pad); 295687d66f28SThierry Reding 295787d66f28SThierry Reding return pad; 295887d66f28SThierry Reding 295987d66f28SThierry Reding unregister: 296087d66f28SThierry Reding device_unregister(&pad->dev); 296187d66f28SThierry Reding out: 296287d66f28SThierry Reding return ERR_PTR(err); 296387d66f28SThierry Reding } 296487d66f28SThierry Reding 296587d66f28SThierry Reding static void tegra210_sata_pad_remove(struct tegra_xusb_pad *pad) 296687d66f28SThierry Reding { 296787d66f28SThierry Reding struct tegra_xusb_sata_pad *sata = to_sata_pad(pad); 296887d66f28SThierry Reding 296987d66f28SThierry Reding kfree(sata); 297087d66f28SThierry Reding } 297187d66f28SThierry Reding 297287d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_sata_ops = { 297387d66f28SThierry Reding .probe = tegra210_sata_pad_probe, 297487d66f28SThierry Reding .remove = tegra210_sata_pad_remove, 297587d66f28SThierry Reding }; 297687d66f28SThierry Reding 297787d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_sata_pad = { 297887d66f28SThierry Reding .name = "sata", 297987d66f28SThierry Reding .num_lanes = ARRAY_SIZE(tegra210_sata_lanes), 298087d66f28SThierry Reding .lanes = tegra210_sata_lanes, 298187d66f28SThierry Reding .ops = &tegra210_sata_ops, 298287d66f28SThierry Reding }; 298387d66f28SThierry Reding 298487d66f28SThierry Reding static const struct tegra_xusb_pad_soc * const tegra210_pads[] = { 298587d66f28SThierry Reding &tegra210_usb2_pad, 298687d66f28SThierry Reding &tegra210_hsic_pad, 298787d66f28SThierry Reding &tegra210_pcie_pad, 298887d66f28SThierry Reding &tegra210_sata_pad, 298987d66f28SThierry Reding }; 299087d66f28SThierry Reding 299187d66f28SThierry Reding static int tegra210_usb2_port_enable(struct tegra_xusb_port *port) 299287d66f28SThierry Reding { 299387d66f28SThierry Reding return 0; 299487d66f28SThierry Reding } 299587d66f28SThierry Reding 299687d66f28SThierry Reding static void tegra210_usb2_port_disable(struct tegra_xusb_port *port) 299787d66f28SThierry Reding { 299887d66f28SThierry Reding } 299987d66f28SThierry Reding 300087d66f28SThierry Reding static struct tegra_xusb_lane * 300187d66f28SThierry Reding tegra210_usb2_port_map(struct tegra_xusb_port *port) 300287d66f28SThierry Reding { 300387d66f28SThierry Reding return tegra_xusb_find_lane(port->padctl, "usb2", port->index); 300487d66f28SThierry Reding } 300587d66f28SThierry Reding 300687d66f28SThierry Reding static const struct tegra_xusb_port_ops tegra210_usb2_port_ops = { 3007e78fdbadSThierry Reding .release = tegra_xusb_usb2_port_release, 30082f8da84dSThierry Reding .remove = tegra_xusb_usb2_port_remove, 300987d66f28SThierry Reding .enable = tegra210_usb2_port_enable, 301087d66f28SThierry Reding .disable = tegra210_usb2_port_disable, 301187d66f28SThierry Reding .map = tegra210_usb2_port_map, 301287d66f28SThierry Reding }; 301387d66f28SThierry Reding 301487d66f28SThierry Reding static int tegra210_hsic_port_enable(struct tegra_xusb_port *port) 301587d66f28SThierry Reding { 301687d66f28SThierry Reding return 0; 301787d66f28SThierry Reding } 301887d66f28SThierry Reding 301987d66f28SThierry Reding static void tegra210_hsic_port_disable(struct tegra_xusb_port *port) 302087d66f28SThierry Reding { 302187d66f28SThierry Reding } 302287d66f28SThierry Reding 302387d66f28SThierry Reding static struct tegra_xusb_lane * 302487d66f28SThierry Reding tegra210_hsic_port_map(struct tegra_xusb_port *port) 302587d66f28SThierry Reding { 302687d66f28SThierry Reding return tegra_xusb_find_lane(port->padctl, "hsic", port->index); 302787d66f28SThierry Reding } 302887d66f28SThierry Reding 302987d66f28SThierry Reding static const struct tegra_xusb_port_ops tegra210_hsic_port_ops = { 3030e78fdbadSThierry Reding .release = tegra_xusb_hsic_port_release, 303187d66f28SThierry Reding .enable = tegra210_hsic_port_enable, 303287d66f28SThierry Reding .disable = tegra210_hsic_port_disable, 303387d66f28SThierry Reding .map = tegra210_hsic_port_map, 303487d66f28SThierry Reding }; 303587d66f28SThierry Reding 303687d66f28SThierry Reding static int tegra210_usb3_port_enable(struct tegra_xusb_port *port) 303787d66f28SThierry Reding { 303887d66f28SThierry Reding return 0; 303987d66f28SThierry Reding } 304087d66f28SThierry Reding 304187d66f28SThierry Reding static void tegra210_usb3_port_disable(struct tegra_xusb_port *port) 304287d66f28SThierry Reding { 304387d66f28SThierry Reding } 304487d66f28SThierry Reding 304587d66f28SThierry Reding static struct tegra_xusb_lane * 304687d66f28SThierry Reding tegra210_usb3_port_map(struct tegra_xusb_port *port) 304787d66f28SThierry Reding { 304887d66f28SThierry Reding return tegra_xusb_port_find_lane(port, tegra210_usb3_map, "usb3-ss"); 304987d66f28SThierry Reding } 305087d66f28SThierry Reding 305187d66f28SThierry Reding static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = { 3052e78fdbadSThierry Reding .release = tegra_xusb_usb3_port_release, 30532f8da84dSThierry Reding .remove = tegra_xusb_usb3_port_remove, 305487d66f28SThierry Reding .enable = tegra210_usb3_port_enable, 305587d66f28SThierry Reding .disable = tegra210_usb3_port_disable, 305687d66f28SThierry Reding .map = tegra210_usb3_port_map, 305787d66f28SThierry Reding }; 305887d66f28SThierry Reding 305990767cdfSNagarjuna Kristam static int tegra210_utmi_port_reset(struct phy *phy) 306090767cdfSNagarjuna Kristam { 306190767cdfSNagarjuna Kristam struct tegra_xusb_padctl *padctl; 306290767cdfSNagarjuna Kristam struct tegra_xusb_lane *lane; 306390767cdfSNagarjuna Kristam u32 value; 306490767cdfSNagarjuna Kristam 306590767cdfSNagarjuna Kristam lane = phy_get_drvdata(phy); 306690767cdfSNagarjuna Kristam padctl = lane->pad->padctl; 306790767cdfSNagarjuna Kristam 306890767cdfSNagarjuna Kristam value = padctl_readl(padctl, 306990767cdfSNagarjuna Kristam XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL0(lane->index)); 307090767cdfSNagarjuna Kristam 307190767cdfSNagarjuna Kristam if ((value & XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIP) || 307290767cdfSNagarjuna Kristam (value & XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIN)) { 307390767cdfSNagarjuna Kristam tegra210_xusb_padctl_vbus_override(padctl, false); 307490767cdfSNagarjuna Kristam tegra210_xusb_padctl_vbus_override(padctl, true); 307590767cdfSNagarjuna Kristam return 1; 307690767cdfSNagarjuna Kristam } 307790767cdfSNagarjuna Kristam 307890767cdfSNagarjuna Kristam return 0; 307990767cdfSNagarjuna Kristam } 308090767cdfSNagarjuna Kristam 308187d66f28SThierry Reding static int 308287d66f28SThierry Reding tegra210_xusb_read_fuse_calibration(struct tegra210_xusb_fuse_calibration *fuse) 308387d66f28SThierry Reding { 308487d66f28SThierry Reding unsigned int i; 308587d66f28SThierry Reding u32 value; 308687d66f28SThierry Reding int err; 308787d66f28SThierry Reding 308887d66f28SThierry Reding err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value); 308987d66f28SThierry Reding if (err < 0) 309087d66f28SThierry Reding return err; 309187d66f28SThierry Reding 309287d66f28SThierry Reding for (i = 0; i < ARRAY_SIZE(fuse->hs_curr_level); i++) { 309387d66f28SThierry Reding fuse->hs_curr_level[i] = 309487d66f28SThierry Reding (value >> FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(i)) & 309587d66f28SThierry Reding FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK; 309687d66f28SThierry Reding } 309787d66f28SThierry Reding 309887d66f28SThierry Reding fuse->hs_term_range_adj = 309987d66f28SThierry Reding (value >> FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT) & 310087d66f28SThierry Reding FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK; 310187d66f28SThierry Reding 310287d66f28SThierry Reding err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value); 310387d66f28SThierry Reding if (err < 0) 310487d66f28SThierry Reding return err; 310587d66f28SThierry Reding 310687d66f28SThierry Reding fuse->rpd_ctrl = 310787d66f28SThierry Reding (value >> FUSE_USB_CALIB_EXT_RPD_CTRL_SHIFT) & 310887d66f28SThierry Reding FUSE_USB_CALIB_EXT_RPD_CTRL_MASK; 310987d66f28SThierry Reding 311087d66f28SThierry Reding return 0; 311187d66f28SThierry Reding } 311287d66f28SThierry Reding 311387d66f28SThierry Reding static struct tegra_xusb_padctl * 311487d66f28SThierry Reding tegra210_xusb_padctl_probe(struct device *dev, 311587d66f28SThierry Reding const struct tegra_xusb_padctl_soc *soc) 311687d66f28SThierry Reding { 311787d66f28SThierry Reding struct tegra210_xusb_padctl *padctl; 3118*2d102148SJC Kuo struct platform_device *pdev; 3119*2d102148SJC Kuo struct device_node *np; 312087d66f28SThierry Reding int err; 312187d66f28SThierry Reding 312287d66f28SThierry Reding padctl = devm_kzalloc(dev, sizeof(*padctl), GFP_KERNEL); 312387d66f28SThierry Reding if (!padctl) 312487d66f28SThierry Reding return ERR_PTR(-ENOMEM); 312587d66f28SThierry Reding 312687d66f28SThierry Reding padctl->base.dev = dev; 312787d66f28SThierry Reding padctl->base.soc = soc; 312887d66f28SThierry Reding 312987d66f28SThierry Reding err = tegra210_xusb_read_fuse_calibration(&padctl->fuse); 313087d66f28SThierry Reding if (err < 0) 313187d66f28SThierry Reding return ERR_PTR(err); 313287d66f28SThierry Reding 3133*2d102148SJC Kuo np = of_parse_phandle(dev->of_node, "nvidia,pmc", 0); 3134*2d102148SJC Kuo if (!np) { 3135*2d102148SJC Kuo dev_warn(dev, "nvidia,pmc property is missing\n"); 3136*2d102148SJC Kuo goto out; 3137*2d102148SJC Kuo } 3138*2d102148SJC Kuo 3139*2d102148SJC Kuo pdev = of_find_device_by_node(np); 3140*2d102148SJC Kuo if (!pdev) { 3141*2d102148SJC Kuo dev_warn(dev, "PMC device is not available\n"); 3142*2d102148SJC Kuo goto out; 3143*2d102148SJC Kuo } 3144*2d102148SJC Kuo 3145*2d102148SJC Kuo if (!platform_get_drvdata(pdev)) 3146*2d102148SJC Kuo return ERR_PTR(-EPROBE_DEFER); 3147*2d102148SJC Kuo 3148*2d102148SJC Kuo padctl->regmap = dev_get_regmap(&pdev->dev, "usb_sleepwalk"); 3149*2d102148SJC Kuo if (!padctl->regmap) 3150*2d102148SJC Kuo dev_info(dev, "failed to find PMC regmap\n"); 3151*2d102148SJC Kuo 3152*2d102148SJC Kuo out: 315387d66f28SThierry Reding return &padctl->base; 315487d66f28SThierry Reding } 315587d66f28SThierry Reding 315687d66f28SThierry Reding static void tegra210_xusb_padctl_remove(struct tegra_xusb_padctl *padctl) 315787d66f28SThierry Reding { 315887d66f28SThierry Reding } 315987d66f28SThierry Reding 3160*2d102148SJC Kuo static void tegra210_xusb_padctl_save(struct tegra_xusb_padctl *padctl) 3161*2d102148SJC Kuo { 3162*2d102148SJC Kuo struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl); 3163*2d102148SJC Kuo 3164*2d102148SJC Kuo priv->context.usb2_pad_mux = 3165*2d102148SJC Kuo padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX); 3166*2d102148SJC Kuo priv->context.usb2_port_cap = 3167*2d102148SJC Kuo padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP); 3168*2d102148SJC Kuo priv->context.ss_port_map = 3169*2d102148SJC Kuo padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); 3170*2d102148SJC Kuo priv->context.usb3_pad_mux = 3171*2d102148SJC Kuo padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); 3172*2d102148SJC Kuo } 3173*2d102148SJC Kuo 3174*2d102148SJC Kuo static void tegra210_xusb_padctl_restore(struct tegra_xusb_padctl *padctl) 3175*2d102148SJC Kuo { 3176*2d102148SJC Kuo struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl); 3177*2d102148SJC Kuo struct tegra_xusb_lane *lane; 3178*2d102148SJC Kuo 3179*2d102148SJC Kuo padctl_writel(padctl, priv->context.usb2_pad_mux, 3180*2d102148SJC Kuo XUSB_PADCTL_USB2_PAD_MUX); 3181*2d102148SJC Kuo padctl_writel(padctl, priv->context.usb2_port_cap, 3182*2d102148SJC Kuo XUSB_PADCTL_USB2_PORT_CAP); 3183*2d102148SJC Kuo padctl_writel(padctl, priv->context.ss_port_map, 3184*2d102148SJC Kuo XUSB_PADCTL_SS_PORT_MAP); 3185*2d102148SJC Kuo 3186*2d102148SJC Kuo list_for_each_entry(lane, &padctl->lanes, list) { 3187*2d102148SJC Kuo if (lane->pad->ops->iddq_enable) 3188*2d102148SJC Kuo tegra210_uphy_lane_iddq_enable(lane); 3189*2d102148SJC Kuo } 3190*2d102148SJC Kuo 3191*2d102148SJC Kuo padctl_writel(padctl, priv->context.usb3_pad_mux, 3192*2d102148SJC Kuo XUSB_PADCTL_USB3_PAD_MUX); 3193*2d102148SJC Kuo 3194*2d102148SJC Kuo list_for_each_entry(lane, &padctl->lanes, list) { 3195*2d102148SJC Kuo if (lane->pad->ops->iddq_disable) 3196*2d102148SJC Kuo tegra210_uphy_lane_iddq_disable(lane); 3197*2d102148SJC Kuo } 3198*2d102148SJC Kuo } 3199*2d102148SJC Kuo 3200*2d102148SJC Kuo static int tegra210_xusb_padctl_suspend_noirq(struct tegra_xusb_padctl *padctl) 3201*2d102148SJC Kuo { 3202*2d102148SJC Kuo mutex_lock(&padctl->lock); 3203*2d102148SJC Kuo 3204*2d102148SJC Kuo tegra210_uphy_deinit(padctl); 3205*2d102148SJC Kuo 3206*2d102148SJC Kuo tegra210_xusb_padctl_save(padctl); 3207*2d102148SJC Kuo 3208*2d102148SJC Kuo mutex_unlock(&padctl->lock); 3209*2d102148SJC Kuo return 0; 3210*2d102148SJC Kuo } 3211*2d102148SJC Kuo 3212*2d102148SJC Kuo static int tegra210_xusb_padctl_resume_noirq(struct tegra_xusb_padctl *padctl) 3213*2d102148SJC Kuo { 3214*2d102148SJC Kuo mutex_lock(&padctl->lock); 3215*2d102148SJC Kuo 3216*2d102148SJC Kuo tegra210_xusb_padctl_restore(padctl); 3217*2d102148SJC Kuo 3218*2d102148SJC Kuo tegra210_uphy_init(padctl); 3219*2d102148SJC Kuo 3220*2d102148SJC Kuo mutex_unlock(&padctl->lock); 3221*2d102148SJC Kuo return 0; 3222*2d102148SJC Kuo } 3223*2d102148SJC Kuo 322487d66f28SThierry Reding static const struct tegra_xusb_padctl_ops tegra210_xusb_padctl_ops = { 322587d66f28SThierry Reding .probe = tegra210_xusb_padctl_probe, 322687d66f28SThierry Reding .remove = tegra210_xusb_padctl_remove, 3227*2d102148SJC Kuo .suspend_noirq = tegra210_xusb_padctl_suspend_noirq, 3228*2d102148SJC Kuo .resume_noirq = tegra210_xusb_padctl_resume_noirq, 322987d66f28SThierry Reding .usb3_set_lfps_detect = tegra210_usb3_set_lfps_detect, 323087d66f28SThierry Reding .hsic_set_idle = tegra210_hsic_set_idle, 323190767cdfSNagarjuna Kristam .vbus_override = tegra210_xusb_padctl_vbus_override, 323290767cdfSNagarjuna Kristam .utmi_port_reset = tegra210_utmi_port_reset, 323387d66f28SThierry Reding }; 323487d66f28SThierry Reding 3235e3888cdaSThierry Reding static const char * const tegra210_xusb_padctl_supply_names[] = { 3236e3888cdaSThierry Reding "avdd-pll-utmip", 3237e3888cdaSThierry Reding "avdd-pll-uerefe", 3238e3888cdaSThierry Reding "dvdd-pex-pll", 3239e3888cdaSThierry Reding "hvdd-pex-pll-e", 3240e3888cdaSThierry Reding }; 3241e3888cdaSThierry Reding 324287d66f28SThierry Reding const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc = { 324387d66f28SThierry Reding .num_pads = ARRAY_SIZE(tegra210_pads), 324487d66f28SThierry Reding .pads = tegra210_pads, 324587d66f28SThierry Reding .ports = { 324687d66f28SThierry Reding .usb2 = { 324787d66f28SThierry Reding .ops = &tegra210_usb2_port_ops, 324887d66f28SThierry Reding .count = 4, 324987d66f28SThierry Reding }, 325087d66f28SThierry Reding .hsic = { 325187d66f28SThierry Reding .ops = &tegra210_hsic_port_ops, 325287d66f28SThierry Reding .count = 1, 325387d66f28SThierry Reding }, 325487d66f28SThierry Reding .usb3 = { 325587d66f28SThierry Reding .ops = &tegra210_usb3_port_ops, 325687d66f28SThierry Reding .count = 4, 325787d66f28SThierry Reding }, 325887d66f28SThierry Reding }, 325987d66f28SThierry Reding .ops = &tegra210_xusb_padctl_ops, 3260e3888cdaSThierry Reding .supply_names = tegra210_xusb_padctl_supply_names, 3261e3888cdaSThierry Reding .num_supplies = ARRAY_SIZE(tegra210_xusb_padctl_supply_names), 3262a5be28c3SNagarjuna Kristam .need_fake_usb3_port = true, 326387d66f28SThierry Reding }; 326487d66f28SThierry Reding EXPORT_SYMBOL_GPL(tegra210_xusb_padctl_soc); 326587d66f28SThierry Reding 326687d66f28SThierry Reding MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>"); 326787d66f28SThierry Reding MODULE_DESCRIPTION("NVIDIA Tegra 210 XUSB Pad Controller driver"); 326887d66f28SThierry Reding MODULE_LICENSE("GPL v2"); 3269