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> 142d102148SJC Kuo #include <linux/of_platform.h> 1587d66f28SThierry Reding #include <linux/phy/phy.h> 1687d66f28SThierry Reding #include <linux/platform_device.h> 172d102148SJC 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 572d102148SJC Kuo #define XUSB_PADCTL_ELPG_PROGRAM_0 0x20 582d102148SJC Kuo #define USB2_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x)) 592d102148SJC Kuo #define USB2_PORT_WAKEUP_EVENT(x) BIT((x) + 7) 602d102148SJC Kuo #define SS_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 14) 612d102148SJC Kuo #define SS_PORT_WAKEUP_EVENT(x) BIT((x) + 21) 622d102148SJC Kuo #define USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 28) 632d102148SJC Kuo #define USB2_HSIC_PORT_WAKEUP_EVENT(x) BIT((x) + 30) 642d102148SJC Kuo #define ALL_WAKE_EVENTS ( \ 652d102148SJC Kuo USB2_PORT_WAKEUP_EVENT(0) | USB2_PORT_WAKEUP_EVENT(1) | \ 662d102148SJC Kuo USB2_PORT_WAKEUP_EVENT(2) | USB2_PORT_WAKEUP_EVENT(3) | \ 672d102148SJC Kuo SS_PORT_WAKEUP_EVENT(0) | SS_PORT_WAKEUP_EVENT(1) | \ 682d102148SJC Kuo SS_PORT_WAKEUP_EVENT(2) | SS_PORT_WAKEUP_EVENT(3) | \ 692d102148SJC Kuo USB2_HSIC_PORT_WAKEUP_EVENT(0)) 702d102148SJC 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) 1092d102148SJC Kuo #define RPD_CTRL(x) (((x) & 0x1f) << 26) 1102d102148SJC 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 1292d102148SJC Kuo #define TCTRL_VALUE(x) (((x) & 0x3f) >> 0) 1302d102148SJC 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 2742d102148SJC Kuo /* USB2 SLEEPWALK registers */ 2752d102148SJC Kuo #define UTMIP(_port, _offset1, _offset2) \ 2762d102148SJC Kuo (((_port) <= 2) ? (_offset1) : (_offset2)) 2772d102148SJC Kuo 2782d102148SJC Kuo #define PMC_UTMIP_UHSIC_SLEEP_CFG(x) UTMIP(x, 0x1fc, 0x4d0) 2792d102148SJC Kuo #define UTMIP_MASTER_ENABLE(x) UTMIP(x, BIT(8 * (x)), BIT(0)) 2802d102148SJC Kuo #define UTMIP_FSLS_USE_PMC(x) UTMIP(x, BIT(8 * (x) + 1), \ 2812d102148SJC Kuo BIT(1)) 2822d102148SJC Kuo #define UTMIP_PCTRL_USE_PMC(x) UTMIP(x, BIT(8 * (x) + 2), \ 2832d102148SJC Kuo BIT(2)) 2842d102148SJC Kuo #define UTMIP_TCTRL_USE_PMC(x) UTMIP(x, BIT(8 * (x) + 3), \ 2852d102148SJC Kuo BIT(3)) 2862d102148SJC Kuo #define UTMIP_WAKE_VAL(_port, _value) (((_value) & 0xf) << \ 2872d102148SJC Kuo (UTMIP(_port, 8 * (_port) + 4, 4))) 2882d102148SJC Kuo #define UTMIP_WAKE_VAL_NONE(_port) UTMIP_WAKE_VAL(_port, 12) 2892d102148SJC Kuo #define UTMIP_WAKE_VAL_ANY(_port) UTMIP_WAKE_VAL(_port, 15) 2902d102148SJC Kuo 2912d102148SJC Kuo #define PMC_UTMIP_UHSIC_SLEEP_CFG1 (0x4d0) 2922d102148SJC Kuo #define UTMIP_RPU_SWITC_LOW_USE_PMC_PX(x) BIT((x) + 8) 2932d102148SJC Kuo #define UTMIP_RPD_CTRL_USE_PMC_PX(x) BIT((x) + 16) 2942d102148SJC Kuo 2952d102148SJC Kuo #define PMC_UTMIP_MASTER_CONFIG (0x274) 2962d102148SJC Kuo #define UTMIP_PWR(x) UTMIP(x, BIT(x), BIT(4)) 2972d102148SJC Kuo #define UHSIC_PWR BIT(3) 2982d102148SJC Kuo 2992d102148SJC Kuo #define PMC_USB_DEBOUNCE_DEL (0xec) 3002d102148SJC Kuo #define DEBOUNCE_VAL(x) (((x) & 0xffff) << 0) 3012d102148SJC Kuo #define UTMIP_LINE_DEB_CNT(x) (((x) & 0xf) << 16) 3022d102148SJC Kuo #define UHSIC_LINE_DEB_CNT(x) (((x) & 0xf) << 20) 3032d102148SJC Kuo 3042d102148SJC Kuo #define PMC_UTMIP_UHSIC_FAKE(x) UTMIP(x, 0x218, 0x294) 3052d102148SJC Kuo #define UTMIP_FAKE_USBOP_VAL(x) UTMIP(x, BIT(4 * (x)), BIT(8)) 3062d102148SJC Kuo #define UTMIP_FAKE_USBON_VAL(x) UTMIP(x, BIT(4 * (x) + 1), \ 3072d102148SJC Kuo BIT(9)) 3082d102148SJC Kuo #define UTMIP_FAKE_USBOP_EN(x) UTMIP(x, BIT(4 * (x) + 2), \ 3092d102148SJC Kuo BIT(10)) 3102d102148SJC Kuo #define UTMIP_FAKE_USBON_EN(x) UTMIP(x, BIT(4 * (x) + 3), \ 3112d102148SJC Kuo BIT(11)) 3122d102148SJC Kuo 3132d102148SJC Kuo #define PMC_UTMIP_UHSIC_SLEEPWALK_CFG(x) UTMIP(x, 0x200, 0x288) 3142d102148SJC Kuo #define UTMIP_LINEVAL_WALK_EN(x) UTMIP(x, BIT(8 * (x) + 7), \ 3152d102148SJC Kuo BIT(15)) 3162d102148SJC Kuo 3172d102148SJC Kuo #define PMC_USB_AO (0xf0) 3182d102148SJC Kuo #define USBOP_VAL_PD(x) UTMIP(x, BIT(4 * (x)), BIT(20)) 3192d102148SJC Kuo #define USBON_VAL_PD(x) UTMIP(x, BIT(4 * (x) + 1), \ 3202d102148SJC Kuo BIT(21)) 3212d102148SJC Kuo #define STROBE_VAL_PD BIT(12) 3222d102148SJC Kuo #define DATA0_VAL_PD BIT(13) 3232d102148SJC Kuo #define DATA1_VAL_PD BIT(24) 3242d102148SJC Kuo 3252d102148SJC Kuo #define PMC_UTMIP_UHSIC_SAVED_STATE(x) UTMIP(x, 0x1f0, 0x280) 3262d102148SJC Kuo #define SPEED(_port, _value) (((_value) & 0x3) << \ 3272d102148SJC Kuo (UTMIP(_port, 8 * (_port), 8))) 3282d102148SJC Kuo #define UTMI_HS(_port) SPEED(_port, 0) 3292d102148SJC Kuo #define UTMI_FS(_port) SPEED(_port, 1) 3302d102148SJC Kuo #define UTMI_LS(_port) SPEED(_port, 2) 3312d102148SJC Kuo #define UTMI_RST(_port) SPEED(_port, 3) 3322d102148SJC Kuo 3332d102148SJC Kuo #define PMC_UTMIP_UHSIC_TRIGGERS (0x1ec) 3342d102148SJC Kuo #define UTMIP_CLR_WALK_PTR(x) UTMIP(x, BIT(x), BIT(16)) 3352d102148SJC Kuo #define UTMIP_CAP_CFG(x) UTMIP(x, BIT((x) + 4), BIT(17)) 3362d102148SJC Kuo #define UTMIP_CLR_WAKE_ALARM(x) UTMIP(x, BIT((x) + 12), \ 3372d102148SJC Kuo BIT(19)) 3382d102148SJC Kuo #define UHSIC_CLR_WALK_PTR BIT(3) 3392d102148SJC Kuo #define UHSIC_CLR_WAKE_ALARM BIT(15) 3402d102148SJC Kuo 3412d102148SJC Kuo #define PMC_UTMIP_SLEEPWALK_PX(x) UTMIP(x, 0x204 + (4 * (x)), \ 3422d102148SJC Kuo 0x4e0) 3432d102148SJC Kuo /* phase A */ 3442d102148SJC Kuo #define UTMIP_USBOP_RPD_A BIT(0) 3452d102148SJC Kuo #define UTMIP_USBON_RPD_A BIT(1) 3462d102148SJC Kuo #define UTMIP_AP_A BIT(4) 3472d102148SJC Kuo #define UTMIP_AN_A BIT(5) 3482d102148SJC Kuo #define UTMIP_HIGHZ_A BIT(6) 3492d102148SJC Kuo /* phase B */ 3502d102148SJC Kuo #define UTMIP_USBOP_RPD_B BIT(8) 3512d102148SJC Kuo #define UTMIP_USBON_RPD_B BIT(9) 3522d102148SJC Kuo #define UTMIP_AP_B BIT(12) 3532d102148SJC Kuo #define UTMIP_AN_B BIT(13) 3542d102148SJC Kuo #define UTMIP_HIGHZ_B BIT(14) 3552d102148SJC Kuo /* phase C */ 3562d102148SJC Kuo #define UTMIP_USBOP_RPD_C BIT(16) 3572d102148SJC Kuo #define UTMIP_USBON_RPD_C BIT(17) 3582d102148SJC Kuo #define UTMIP_AP_C BIT(20) 3592d102148SJC Kuo #define UTMIP_AN_C BIT(21) 3602d102148SJC Kuo #define UTMIP_HIGHZ_C BIT(22) 3612d102148SJC Kuo /* phase D */ 3622d102148SJC Kuo #define UTMIP_USBOP_RPD_D BIT(24) 3632d102148SJC Kuo #define UTMIP_USBON_RPD_D BIT(25) 3642d102148SJC Kuo #define UTMIP_AP_D BIT(28) 3652d102148SJC Kuo #define UTMIP_AN_D BIT(29) 3662d102148SJC Kuo #define UTMIP_HIGHZ_D BIT(30) 3672d102148SJC Kuo 3682d102148SJC Kuo #define PMC_UTMIP_UHSIC_LINE_WAKEUP (0x26c) 3692d102148SJC Kuo #define UTMIP_LINE_WAKEUP_EN(x) UTMIP(x, BIT(x), BIT(4)) 3702d102148SJC Kuo #define UHSIC_LINE_WAKEUP_EN BIT(3) 3712d102148SJC Kuo 3722d102148SJC Kuo #define PMC_UTMIP_TERM_PAD_CFG (0x1f8) 3732d102148SJC Kuo #define PCTRL_VAL(x) (((x) & 0x3f) << 1) 3742d102148SJC Kuo #define TCTRL_VAL(x) (((x) & 0x3f) << 7) 3752d102148SJC Kuo 3762d102148SJC Kuo #define PMC_UTMIP_PAD_CFGX(x) (0x4c0 + (4 * (x))) 3772d102148SJC Kuo #define RPD_CTRL_PX(x) (((x) & 0x1f) << 22) 3782d102148SJC Kuo 3792d102148SJC Kuo #define PMC_UHSIC_SLEEP_CFG PMC_UTMIP_UHSIC_SLEEP_CFG(0) 3802d102148SJC Kuo #define UHSIC_MASTER_ENABLE BIT(24) 3812d102148SJC Kuo #define UHSIC_WAKE_VAL(_value) (((_value) & 0xf) << 28) 3822d102148SJC Kuo #define UHSIC_WAKE_VAL_SD10 UHSIC_WAKE_VAL(2) 3832d102148SJC Kuo #define UHSIC_WAKE_VAL_NONE UHSIC_WAKE_VAL(12) 3842d102148SJC Kuo 3852d102148SJC Kuo #define PMC_UHSIC_FAKE PMC_UTMIP_UHSIC_FAKE(0) 3862d102148SJC Kuo #define UHSIC_FAKE_STROBE_VAL BIT(12) 3872d102148SJC Kuo #define UHSIC_FAKE_DATA_VAL BIT(13) 3882d102148SJC Kuo #define UHSIC_FAKE_STROBE_EN BIT(14) 3892d102148SJC Kuo #define UHSIC_FAKE_DATA_EN BIT(15) 3902d102148SJC Kuo 3912d102148SJC Kuo #define PMC_UHSIC_SAVED_STATE PMC_UTMIP_UHSIC_SAVED_STATE(0) 3922d102148SJC Kuo #define UHSIC_MODE(_value) (((_value) & 0x1) << 24) 3932d102148SJC Kuo #define UHSIC_HS UHSIC_MODE(0) 3942d102148SJC Kuo #define UHSIC_RST UHSIC_MODE(1) 3952d102148SJC Kuo 3962d102148SJC Kuo #define PMC_UHSIC_SLEEPWALK_CFG PMC_UTMIP_UHSIC_SLEEPWALK_CFG(0) 3972d102148SJC Kuo #define UHSIC_WAKE_WALK_EN BIT(30) 3982d102148SJC Kuo #define UHSIC_LINEVAL_WALK_EN BIT(31) 3992d102148SJC Kuo 4002d102148SJC Kuo #define PMC_UHSIC_SLEEPWALK_P0 (0x210) 4012d102148SJC Kuo #define UHSIC_DATA0_RPD_A BIT(1) 4022d102148SJC Kuo #define UHSIC_DATA0_RPU_B BIT(11) 4032d102148SJC Kuo #define UHSIC_DATA0_RPU_C BIT(19) 4042d102148SJC Kuo #define UHSIC_DATA0_RPU_D BIT(27) 4052d102148SJC Kuo #define UHSIC_STROBE_RPU_A BIT(2) 4062d102148SJC Kuo #define UHSIC_STROBE_RPD_B BIT(8) 4072d102148SJC Kuo #define UHSIC_STROBE_RPD_C BIT(16) 4082d102148SJC Kuo #define UHSIC_STROBE_RPD_D BIT(24) 4092d102148SJC 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 4162d102148SJC Kuo struct tegra210_xusb_padctl_context { 4172d102148SJC Kuo u32 usb2_pad_mux; 4182d102148SJC Kuo u32 usb2_port_cap; 4192d102148SJC Kuo u32 ss_port_map; 4202d102148SJC Kuo u32 usb3_pad_mux; 4212d102148SJC Kuo }; 4222d102148SJC Kuo 42387d66f28SThierry Reding struct tegra210_xusb_padctl { 42487d66f28SThierry Reding struct tegra_xusb_padctl base; 4252d102148SJC Kuo struct regmap *regmap; 42687d66f28SThierry Reding 42787d66f28SThierry Reding struct tegra210_xusb_fuse_calibration fuse; 4282d102148SJC 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 10582d102148SJC Kuo static int tegra210_usb3_enable_phy_sleepwalk(struct tegra_xusb_lane *lane, 10592d102148SJC Kuo enum usb_device_speed speed) 10602d102148SJC Kuo { 10612d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 10622d102148SJC Kuo int port = tegra210_usb3_lane_map(lane); 10632d102148SJC Kuo struct device *dev = padctl->dev; 10642d102148SJC Kuo u32 value; 10652d102148SJC Kuo 10662d102148SJC Kuo if (port < 0) { 10672d102148SJC Kuo dev_err(dev, "invalid usb3 port number\n"); 10682d102148SJC Kuo return -EINVAL; 10692d102148SJC Kuo } 10702d102148SJC Kuo 10712d102148SJC Kuo mutex_lock(&padctl->lock); 10722d102148SJC Kuo 10732d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 10742d102148SJC Kuo value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port); 10752d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 10762d102148SJC Kuo 10772d102148SJC Kuo usleep_range(100, 200); 10782d102148SJC Kuo 10792d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 10802d102148SJC Kuo value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port); 10812d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 10822d102148SJC Kuo 10832d102148SJC Kuo usleep_range(250, 350); 10842d102148SJC Kuo 10852d102148SJC Kuo mutex_unlock(&padctl->lock); 10862d102148SJC Kuo 10872d102148SJC Kuo return 0; 10882d102148SJC Kuo } 10892d102148SJC Kuo 10902d102148SJC Kuo static int tegra210_usb3_disable_phy_sleepwalk(struct tegra_xusb_lane *lane) 10912d102148SJC Kuo { 10922d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 10932d102148SJC Kuo int port = tegra210_usb3_lane_map(lane); 10942d102148SJC Kuo struct device *dev = padctl->dev; 10952d102148SJC Kuo u32 value; 10962d102148SJC Kuo 10972d102148SJC Kuo if (port < 0) { 10982d102148SJC Kuo dev_err(dev, "invalid usb3 port number\n"); 10992d102148SJC Kuo return -EINVAL; 11002d102148SJC Kuo } 11012d102148SJC Kuo 11022d102148SJC Kuo mutex_lock(&padctl->lock); 11032d102148SJC Kuo 11042d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 11052d102148SJC Kuo value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port); 11062d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 11072d102148SJC Kuo 11082d102148SJC Kuo usleep_range(100, 200); 11092d102148SJC Kuo 11102d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 11112d102148SJC Kuo value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port); 11122d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 11132d102148SJC Kuo 11142d102148SJC Kuo mutex_unlock(&padctl->lock); 11152d102148SJC Kuo 11162d102148SJC Kuo return 0; 11172d102148SJC Kuo } 11182d102148SJC Kuo 11192d102148SJC Kuo static int tegra210_usb3_enable_phy_wake(struct tegra_xusb_lane *lane) 11202d102148SJC Kuo { 11212d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 11222d102148SJC Kuo int port = tegra210_usb3_lane_map(lane); 11232d102148SJC Kuo struct device *dev = padctl->dev; 11242d102148SJC Kuo u32 value; 11252d102148SJC Kuo 11262d102148SJC Kuo if (port < 0) { 11272d102148SJC Kuo dev_err(dev, "invalid usb3 port number\n"); 11282d102148SJC Kuo return -EINVAL; 11292d102148SJC Kuo } 11302d102148SJC Kuo 11312d102148SJC Kuo mutex_lock(&padctl->lock); 11322d102148SJC Kuo 11332d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 11342d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 11352d102148SJC Kuo value |= SS_PORT_WAKEUP_EVENT(port); 11362d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 11372d102148SJC Kuo 11382d102148SJC Kuo usleep_range(10, 20); 11392d102148SJC Kuo 11402d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 11412d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 11422d102148SJC Kuo value |= SS_PORT_WAKE_INTERRUPT_ENABLE(port); 11432d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 11442d102148SJC Kuo 11452d102148SJC Kuo mutex_unlock(&padctl->lock); 11462d102148SJC Kuo 11472d102148SJC Kuo return 0; 11482d102148SJC Kuo } 11492d102148SJC Kuo 11502d102148SJC Kuo static int tegra210_usb3_disable_phy_wake(struct tegra_xusb_lane *lane) 11512d102148SJC Kuo { 11522d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 11532d102148SJC Kuo int port = tegra210_usb3_lane_map(lane); 11542d102148SJC Kuo struct device *dev = padctl->dev; 11552d102148SJC Kuo u32 value; 11562d102148SJC Kuo 11572d102148SJC Kuo if (port < 0) { 11582d102148SJC Kuo dev_err(dev, "invalid usb3 port number\n"); 11592d102148SJC Kuo return -EINVAL; 11602d102148SJC Kuo } 11612d102148SJC Kuo 11622d102148SJC Kuo mutex_lock(&padctl->lock); 11632d102148SJC Kuo 11642d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 11652d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 11662d102148SJC Kuo value &= ~SS_PORT_WAKE_INTERRUPT_ENABLE(port); 11672d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 11682d102148SJC Kuo 11692d102148SJC Kuo usleep_range(10, 20); 11702d102148SJC Kuo 11712d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 11722d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 11732d102148SJC Kuo value |= SS_PORT_WAKEUP_EVENT(port); 11742d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 11752d102148SJC Kuo 11762d102148SJC Kuo mutex_unlock(&padctl->lock); 11772d102148SJC Kuo 11782d102148SJC Kuo return 0; 11792d102148SJC Kuo } 11802d102148SJC Kuo 11812d102148SJC Kuo static bool tegra210_usb3_phy_remote_wake_detected(struct tegra_xusb_lane *lane) 11822d102148SJC Kuo { 11832d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 11842d102148SJC Kuo int index = tegra210_usb3_lane_map(lane); 11852d102148SJC Kuo u32 value; 11862d102148SJC Kuo 11872d102148SJC Kuo if (index < 0) 11882d102148SJC Kuo return false; 11892d102148SJC Kuo 11902d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 11912d102148SJC Kuo if ((value & SS_PORT_WAKE_INTERRUPT_ENABLE(index)) && (value & SS_PORT_WAKEUP_EVENT(index))) 11922d102148SJC Kuo return true; 11932d102148SJC Kuo 11942d102148SJC Kuo return false; 11952d102148SJC Kuo } 11962d102148SJC Kuo 11972d102148SJC Kuo static int tegra210_utmi_enable_phy_wake(struct tegra_xusb_lane *lane) 11982d102148SJC Kuo { 11992d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 12002d102148SJC Kuo unsigned int index = lane->index; 12012d102148SJC Kuo u32 value; 12022d102148SJC Kuo 12032d102148SJC Kuo mutex_lock(&padctl->lock); 12042d102148SJC Kuo 12052d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 12062d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 12072d102148SJC Kuo value |= USB2_PORT_WAKEUP_EVENT(index); 12082d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 12092d102148SJC Kuo 12102d102148SJC Kuo usleep_range(10, 20); 12112d102148SJC Kuo 12122d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 12132d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 12142d102148SJC Kuo value |= USB2_PORT_WAKE_INTERRUPT_ENABLE(index); 12152d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 12162d102148SJC Kuo 12172d102148SJC Kuo mutex_unlock(&padctl->lock); 12182d102148SJC Kuo 12192d102148SJC Kuo return 0; 12202d102148SJC Kuo } 12212d102148SJC Kuo 12222d102148SJC Kuo static int tegra210_utmi_disable_phy_wake(struct tegra_xusb_lane *lane) 12232d102148SJC Kuo { 12242d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 12252d102148SJC Kuo unsigned int index = lane->index; 12262d102148SJC Kuo u32 value; 12272d102148SJC Kuo 12282d102148SJC Kuo mutex_lock(&padctl->lock); 12292d102148SJC Kuo 12302d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 12312d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 12322d102148SJC Kuo value &= ~USB2_PORT_WAKE_INTERRUPT_ENABLE(index); 12332d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 12342d102148SJC Kuo 12352d102148SJC Kuo usleep_range(10, 20); 12362d102148SJC Kuo 12372d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 12382d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 12392d102148SJC Kuo value |= USB2_PORT_WAKEUP_EVENT(index); 12402d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 12412d102148SJC Kuo 12422d102148SJC Kuo mutex_unlock(&padctl->lock); 12432d102148SJC Kuo 12442d102148SJC Kuo return 0; 12452d102148SJC Kuo } 12462d102148SJC Kuo 12472d102148SJC Kuo static bool tegra210_utmi_phy_remote_wake_detected(struct tegra_xusb_lane *lane) 12482d102148SJC Kuo { 12492d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 12502d102148SJC Kuo unsigned int index = lane->index; 12512d102148SJC Kuo u32 value; 12522d102148SJC Kuo 12532d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 12542d102148SJC Kuo if ((value & USB2_PORT_WAKE_INTERRUPT_ENABLE(index)) && 12552d102148SJC Kuo (value & USB2_PORT_WAKEUP_EVENT(index))) 12562d102148SJC Kuo return true; 12572d102148SJC Kuo 12582d102148SJC Kuo return false; 12592d102148SJC Kuo } 12602d102148SJC Kuo 12612d102148SJC Kuo static int tegra210_hsic_enable_phy_wake(struct tegra_xusb_lane *lane) 12622d102148SJC Kuo { 12632d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 12642d102148SJC Kuo unsigned int index = lane->index; 12652d102148SJC Kuo u32 value; 12662d102148SJC Kuo 12672d102148SJC Kuo mutex_lock(&padctl->lock); 12682d102148SJC Kuo 12692d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 12702d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 12712d102148SJC Kuo value |= USB2_HSIC_PORT_WAKEUP_EVENT(index); 12722d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 12732d102148SJC Kuo 12742d102148SJC Kuo usleep_range(10, 20); 12752d102148SJC Kuo 12762d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 12772d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 12782d102148SJC Kuo value |= USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index); 12792d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 12802d102148SJC Kuo 12812d102148SJC Kuo mutex_unlock(&padctl->lock); 12822d102148SJC Kuo 12832d102148SJC Kuo return 0; 12842d102148SJC Kuo } 12852d102148SJC Kuo 12862d102148SJC Kuo static int tegra210_hsic_disable_phy_wake(struct tegra_xusb_lane *lane) 12872d102148SJC Kuo { 12882d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 12892d102148SJC Kuo unsigned int index = lane->index; 12902d102148SJC Kuo u32 value; 12912d102148SJC Kuo 12922d102148SJC Kuo mutex_lock(&padctl->lock); 12932d102148SJC Kuo 12942d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 12952d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 12962d102148SJC Kuo value &= ~USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index); 12972d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 12982d102148SJC Kuo 12992d102148SJC Kuo usleep_range(10, 20); 13002d102148SJC Kuo 13012d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 13022d102148SJC Kuo value &= ~ALL_WAKE_EVENTS; 13032d102148SJC Kuo value |= USB2_HSIC_PORT_WAKEUP_EVENT(index); 13042d102148SJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0); 13052d102148SJC Kuo 13062d102148SJC Kuo mutex_unlock(&padctl->lock); 13072d102148SJC Kuo 13082d102148SJC Kuo return 0; 13092d102148SJC Kuo } 13102d102148SJC Kuo 13112d102148SJC Kuo static bool tegra210_hsic_phy_remote_wake_detected(struct tegra_xusb_lane *lane) 13122d102148SJC Kuo { 13132d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 13142d102148SJC Kuo unsigned int index = lane->index; 13152d102148SJC Kuo u32 value; 13162d102148SJC Kuo 13172d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0); 13182d102148SJC Kuo if ((value & USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index)) && 13192d102148SJC Kuo (value & USB2_HSIC_PORT_WAKEUP_EVENT(index))) 13202d102148SJC Kuo return true; 13212d102148SJC Kuo 13222d102148SJC Kuo return false; 13232d102148SJC Kuo } 13242d102148SJC Kuo 13252d102148SJC Kuo #define padctl_pmc_readl(_priv, _offset) \ 13262d102148SJC Kuo ({ \ 13272d102148SJC Kuo u32 value; \ 13282d102148SJC Kuo WARN(regmap_read(_priv->regmap, _offset, &value), "read %s failed\n", #_offset);\ 13292d102148SJC Kuo value; \ 13302d102148SJC Kuo }) 13312d102148SJC Kuo 13322d102148SJC Kuo #define padctl_pmc_writel(_priv, _value, _offset) \ 13332d102148SJC Kuo WARN(regmap_write(_priv->regmap, _offset, _value), "write %s failed\n", #_offset) 13342d102148SJC Kuo 13352d102148SJC Kuo static int tegra210_pmc_utmi_enable_phy_sleepwalk(struct tegra_xusb_lane *lane, 13362d102148SJC Kuo enum usb_device_speed speed) 13372d102148SJC Kuo { 13382d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 13392d102148SJC Kuo struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl); 13402d102148SJC Kuo unsigned int port = lane->index; 13412d102148SJC Kuo u32 value, tctrl, pctrl, rpd_ctrl; 13422d102148SJC Kuo 13432d102148SJC Kuo if (!priv->regmap) 13442d102148SJC Kuo return -EOPNOTSUPP; 13452d102148SJC Kuo 13462d102148SJC Kuo if (speed > USB_SPEED_HIGH) 13472d102148SJC Kuo return -EINVAL; 13482d102148SJC Kuo 13492d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 13502d102148SJC Kuo tctrl = TCTRL_VALUE(value); 13512d102148SJC Kuo pctrl = PCTRL_VALUE(value); 13522d102148SJC Kuo 13532d102148SJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port)); 13542d102148SJC Kuo rpd_ctrl = RPD_CTRL_VALUE(value); 13552d102148SJC Kuo 13562d102148SJC Kuo /* ensure sleepwalk logic is disabled */ 13572d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 13582d102148SJC Kuo value &= ~UTMIP_MASTER_ENABLE(port); 13592d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 13602d102148SJC Kuo 13612d102148SJC Kuo /* ensure sleepwalk logics are in low power mode */ 13622d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG); 13632d102148SJC Kuo value |= UTMIP_PWR(port); 13642d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG); 13652d102148SJC Kuo 13662d102148SJC Kuo /* set debounce time */ 13672d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL); 13682d102148SJC Kuo value &= ~UTMIP_LINE_DEB_CNT(~0); 13692d102148SJC Kuo value |= UTMIP_LINE_DEB_CNT(0x1); 13702d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_DEBOUNCE_DEL); 13712d102148SJC Kuo 13722d102148SJC Kuo /* ensure fake events of sleepwalk logic are desiabled */ 13732d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_FAKE(port)); 13742d102148SJC Kuo value &= ~(UTMIP_FAKE_USBOP_VAL(port) | UTMIP_FAKE_USBON_VAL(port) | 13752d102148SJC Kuo UTMIP_FAKE_USBOP_EN(port) | UTMIP_FAKE_USBON_EN(port)); 13762d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_FAKE(port)); 13772d102148SJC Kuo 13782d102148SJC Kuo /* ensure wake events of sleepwalk logic are not latched */ 13792d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP); 13802d102148SJC Kuo value &= ~UTMIP_LINE_WAKEUP_EN(port); 13812d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP); 13822d102148SJC Kuo 13832d102148SJC Kuo /* disable wake event triggers of sleepwalk logic */ 13842d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 13852d102148SJC Kuo value &= ~UTMIP_WAKE_VAL(port, ~0); 13862d102148SJC Kuo value |= UTMIP_WAKE_VAL_NONE(port); 13872d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 13882d102148SJC Kuo 13892d102148SJC Kuo /* power down the line state detectors of the pad */ 13902d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_AO); 13912d102148SJC Kuo value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port)); 13922d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_AO); 13932d102148SJC Kuo 13942d102148SJC Kuo /* save state per speed */ 13952d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SAVED_STATE(port)); 13962d102148SJC Kuo value &= ~SPEED(port, ~0); 13972d102148SJC Kuo 13982d102148SJC Kuo switch (speed) { 13992d102148SJC Kuo case USB_SPEED_HIGH: 14002d102148SJC Kuo value |= UTMI_HS(port); 14012d102148SJC Kuo break; 14022d102148SJC Kuo 14032d102148SJC Kuo case USB_SPEED_FULL: 14042d102148SJC Kuo value |= UTMI_FS(port); 14052d102148SJC Kuo break; 14062d102148SJC Kuo 14072d102148SJC Kuo case USB_SPEED_LOW: 14082d102148SJC Kuo value |= UTMI_LS(port); 14092d102148SJC Kuo break; 14102d102148SJC Kuo 14112d102148SJC Kuo default: 14122d102148SJC Kuo value |= UTMI_RST(port); 14132d102148SJC Kuo break; 14142d102148SJC Kuo } 14152d102148SJC Kuo 14162d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SAVED_STATE(port)); 14172d102148SJC Kuo 14182d102148SJC Kuo /* enable the trigger of the sleepwalk logic */ 14192d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port)); 14202d102148SJC Kuo value |= UTMIP_LINEVAL_WALK_EN(port); 14212d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port)); 14222d102148SJC Kuo 14232d102148SJC Kuo /* 14242d102148SJC Kuo * Reset the walk pointer and clear the alarm of the sleepwalk logic, 14252d102148SJC Kuo * as well as capture the configuration of the USB2.0 pad. 14262d102148SJC Kuo */ 14272d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS); 14282d102148SJC Kuo value |= UTMIP_CLR_WALK_PTR(port) | UTMIP_CLR_WAKE_ALARM(port) | UTMIP_CAP_CFG(port); 14292d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS); 14302d102148SJC Kuo 14312d102148SJC Kuo /* program electrical parameters read from XUSB PADCTL */ 14322d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_TERM_PAD_CFG); 14332d102148SJC Kuo value &= ~(TCTRL_VAL(~0) | PCTRL_VAL(~0)); 14342d102148SJC Kuo value |= (TCTRL_VAL(tctrl) | PCTRL_VAL(pctrl)); 14352d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_TERM_PAD_CFG); 14362d102148SJC Kuo 14372d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_PAD_CFGX(port)); 14382d102148SJC Kuo value &= ~RPD_CTRL_PX(~0); 14392d102148SJC Kuo value |= RPD_CTRL_PX(rpd_ctrl); 14402d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_PAD_CFGX(port)); 14412d102148SJC Kuo 14422d102148SJC Kuo /* 14432d102148SJC Kuo * Set up the pull-ups and pull-downs of the signals during the four 14442d102148SJC Kuo * stages of sleepwalk. If a device is connected, program sleepwalk 14452d102148SJC Kuo * logic to maintain a J and keep driving K upon seeing remote wake. 14462d102148SJC Kuo */ 14472d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_SLEEPWALK_PX(port)); 14482d102148SJC Kuo value = UTMIP_USBOP_RPD_A | UTMIP_USBOP_RPD_B | UTMIP_USBOP_RPD_C | UTMIP_USBOP_RPD_D; 14492d102148SJC Kuo value |= UTMIP_USBON_RPD_A | UTMIP_USBON_RPD_B | UTMIP_USBON_RPD_C | UTMIP_USBON_RPD_D; 14502d102148SJC Kuo 14512d102148SJC Kuo switch (speed) { 14522d102148SJC Kuo case USB_SPEED_HIGH: 14532d102148SJC Kuo case USB_SPEED_FULL: 14542d102148SJC Kuo /* J state: D+/D- = high/low, K state: D+/D- = low/high */ 14552d102148SJC Kuo value |= UTMIP_HIGHZ_A; 14562d102148SJC Kuo value |= UTMIP_AP_A; 14572d102148SJC Kuo value |= UTMIP_AN_B | UTMIP_AN_C | UTMIP_AN_D; 14582d102148SJC Kuo break; 14592d102148SJC Kuo 14602d102148SJC Kuo case USB_SPEED_LOW: 14612d102148SJC Kuo /* J state: D+/D- = low/high, K state: D+/D- = high/low */ 14622d102148SJC Kuo value |= UTMIP_HIGHZ_A; 14632d102148SJC Kuo value |= UTMIP_AN_A; 14642d102148SJC Kuo value |= UTMIP_AP_B | UTMIP_AP_C | UTMIP_AP_D; 14652d102148SJC Kuo break; 14662d102148SJC Kuo 14672d102148SJC Kuo default: 14682d102148SJC Kuo value |= UTMIP_HIGHZ_A | UTMIP_HIGHZ_B | UTMIP_HIGHZ_C | UTMIP_HIGHZ_D; 14692d102148SJC Kuo break; 14702d102148SJC Kuo } 14712d102148SJC Kuo 14722d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_SLEEPWALK_PX(port)); 14732d102148SJC Kuo 14742d102148SJC Kuo /* power up the line state detectors of the pad */ 14752d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_AO); 14762d102148SJC Kuo value &= ~(USBOP_VAL_PD(port) | USBON_VAL_PD(port)); 14772d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_AO); 14782d102148SJC Kuo 14792d102148SJC Kuo usleep_range(50, 100); 14802d102148SJC Kuo 14812d102148SJC Kuo /* switch the electric control of the USB2.0 pad to PMC */ 14822d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 14832d102148SJC Kuo value |= UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) | UTMIP_TCTRL_USE_PMC(port); 14842d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 14852d102148SJC Kuo 14862d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1); 14872d102148SJC Kuo value |= UTMIP_RPD_CTRL_USE_PMC_PX(port) | UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port); 14882d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1); 14892d102148SJC Kuo 14902d102148SJC Kuo /* set the wake signaling trigger events */ 14912d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 14922d102148SJC Kuo value &= ~UTMIP_WAKE_VAL(port, ~0); 14932d102148SJC Kuo value |= UTMIP_WAKE_VAL_ANY(port); 14942d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 14952d102148SJC Kuo 14962d102148SJC Kuo /* enable the wake detection */ 14972d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 14982d102148SJC Kuo value |= UTMIP_MASTER_ENABLE(port); 14992d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 15002d102148SJC Kuo 15012d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP); 15022d102148SJC Kuo value |= UTMIP_LINE_WAKEUP_EN(port); 15032d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP); 15042d102148SJC Kuo 15052d102148SJC Kuo return 0; 15062d102148SJC Kuo } 15072d102148SJC Kuo 15082d102148SJC Kuo static int tegra210_pmc_utmi_disable_phy_sleepwalk(struct tegra_xusb_lane *lane) 15092d102148SJC Kuo { 15102d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 15112d102148SJC Kuo struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl); 15122d102148SJC Kuo unsigned int port = lane->index; 15132d102148SJC Kuo u32 value; 15142d102148SJC Kuo 15152d102148SJC Kuo if (!priv->regmap) 15162d102148SJC Kuo return -EOPNOTSUPP; 15172d102148SJC Kuo 15182d102148SJC Kuo /* disable the wake detection */ 15192d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 15202d102148SJC Kuo value &= ~UTMIP_MASTER_ENABLE(port); 15212d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 15222d102148SJC Kuo 15232d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP); 15242d102148SJC Kuo value &= ~UTMIP_LINE_WAKEUP_EN(port); 15252d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP); 15262d102148SJC Kuo 15272d102148SJC Kuo /* switch the electric control of the USB2.0 pad to XUSB or USB2 */ 15282d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 15292d102148SJC Kuo value &= ~(UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) | 15302d102148SJC Kuo UTMIP_TCTRL_USE_PMC(port)); 15312d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 15322d102148SJC Kuo 15332d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1); 15342d102148SJC Kuo value &= ~(UTMIP_RPD_CTRL_USE_PMC_PX(port) | UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port)); 15352d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1); 15362d102148SJC Kuo 15372d102148SJC Kuo /* disable wake event triggers of sleepwalk logic */ 15382d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 15392d102148SJC Kuo value &= ~UTMIP_WAKE_VAL(port, ~0); 15402d102148SJC Kuo value |= UTMIP_WAKE_VAL_NONE(port); 15412d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port)); 15422d102148SJC Kuo 15432d102148SJC Kuo /* power down the line state detectors of the port */ 15442d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_AO); 15452d102148SJC Kuo value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port)); 15462d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_AO); 15472d102148SJC Kuo 15482d102148SJC Kuo /* clear alarm of the sleepwalk logic */ 15492d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS); 15502d102148SJC Kuo value |= UTMIP_CLR_WAKE_ALARM(port); 15512d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS); 15522d102148SJC Kuo 15532d102148SJC Kuo return 0; 15542d102148SJC Kuo } 15552d102148SJC Kuo 15562d102148SJC Kuo static int tegra210_pmc_hsic_enable_phy_sleepwalk(struct tegra_xusb_lane *lane, 15572d102148SJC Kuo enum usb_device_speed speed) 15582d102148SJC Kuo { 15592d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 15602d102148SJC Kuo struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl); 15612d102148SJC Kuo u32 value; 15622d102148SJC Kuo 15632d102148SJC Kuo if (!priv->regmap) 15642d102148SJC Kuo return -EOPNOTSUPP; 15652d102148SJC Kuo 15662d102148SJC Kuo /* ensure sleepwalk logic is disabled */ 15672d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG); 15682d102148SJC Kuo value &= ~UHSIC_MASTER_ENABLE; 15692d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG); 15702d102148SJC Kuo 15712d102148SJC Kuo /* ensure sleepwalk logics are in low power mode */ 15722d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG); 15732d102148SJC Kuo value |= UHSIC_PWR; 15742d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG); 15752d102148SJC Kuo 15762d102148SJC Kuo /* set debounce time */ 15772d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL); 15782d102148SJC Kuo value &= ~UHSIC_LINE_DEB_CNT(~0); 15792d102148SJC Kuo value |= UHSIC_LINE_DEB_CNT(0x1); 15802d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_DEBOUNCE_DEL); 15812d102148SJC Kuo 15822d102148SJC Kuo /* ensure fake events of sleepwalk logic are desiabled */ 15832d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_FAKE); 15842d102148SJC Kuo value &= ~(UHSIC_FAKE_STROBE_VAL | UHSIC_FAKE_DATA_VAL | 15852d102148SJC Kuo UHSIC_FAKE_STROBE_EN | UHSIC_FAKE_DATA_EN); 15862d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_FAKE); 15872d102148SJC Kuo 15882d102148SJC Kuo /* ensure wake events of sleepwalk logic are not latched */ 15892d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP); 15902d102148SJC Kuo value &= ~UHSIC_LINE_WAKEUP_EN; 15912d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP); 15922d102148SJC Kuo 15932d102148SJC Kuo /* disable wake event triggers of sleepwalk logic */ 15942d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG); 15952d102148SJC Kuo value &= ~UHSIC_WAKE_VAL(~0); 15962d102148SJC Kuo value |= UHSIC_WAKE_VAL_NONE; 15972d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG); 15982d102148SJC Kuo 15992d102148SJC Kuo /* power down the line state detectors of the port */ 16002d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_AO); 16012d102148SJC Kuo value |= STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD; 16022d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_AO); 16032d102148SJC Kuo 16042d102148SJC Kuo /* save state, HSIC always comes up as HS */ 16052d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SAVED_STATE); 16062d102148SJC Kuo value &= ~UHSIC_MODE(~0); 16072d102148SJC Kuo value |= UHSIC_HS; 16082d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SAVED_STATE); 16092d102148SJC Kuo 16102d102148SJC Kuo /* enable the trigger of the sleepwalk logic */ 16112d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_CFG); 16122d102148SJC Kuo value |= UHSIC_WAKE_WALK_EN | UHSIC_LINEVAL_WALK_EN; 16132d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_CFG); 16142d102148SJC Kuo 16152d102148SJC Kuo /* 16162d102148SJC Kuo * Reset the walk pointer and clear the alarm of the sleepwalk logic, 16172d102148SJC Kuo * as well as capture the configuration of the USB2.0 port. 16182d102148SJC Kuo */ 16192d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS); 16202d102148SJC Kuo value |= UHSIC_CLR_WALK_PTR | UHSIC_CLR_WAKE_ALARM; 16212d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS); 16222d102148SJC Kuo 16232d102148SJC Kuo /* 16242d102148SJC Kuo * Set up the pull-ups and pull-downs of the signals during the four 16252d102148SJC Kuo * stages of sleepwalk. Maintain a HSIC IDLE and keep driving HSIC 16262d102148SJC Kuo * RESUME upon remote wake. 16272d102148SJC Kuo */ 16282d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_P0); 16292d102148SJC Kuo value = UHSIC_DATA0_RPD_A | UHSIC_DATA0_RPU_B | UHSIC_DATA0_RPU_C | UHSIC_DATA0_RPU_D | 16302d102148SJC Kuo UHSIC_STROBE_RPU_A | UHSIC_STROBE_RPD_B | UHSIC_STROBE_RPD_C | UHSIC_STROBE_RPD_D; 16312d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_P0); 16322d102148SJC Kuo 16332d102148SJC Kuo /* power up the line state detectors of the port */ 16342d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_AO); 16352d102148SJC Kuo value &= ~(STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD); 16362d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_AO); 16372d102148SJC Kuo 16382d102148SJC Kuo usleep_range(50, 100); 16392d102148SJC Kuo 16402d102148SJC Kuo /* set the wake signaling trigger events */ 16412d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG); 16422d102148SJC Kuo value &= ~UHSIC_WAKE_VAL(~0); 16432d102148SJC Kuo value |= UHSIC_WAKE_VAL_SD10; 16442d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG); 16452d102148SJC Kuo 16462d102148SJC Kuo /* enable the wake detection */ 16472d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG); 16482d102148SJC Kuo value |= UHSIC_MASTER_ENABLE; 16492d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG); 16502d102148SJC Kuo 16512d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP); 16522d102148SJC Kuo value |= UHSIC_LINE_WAKEUP_EN; 16532d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP); 16542d102148SJC Kuo 16552d102148SJC Kuo return 0; 16562d102148SJC Kuo } 16572d102148SJC Kuo 16582d102148SJC Kuo static int tegra210_pmc_hsic_disable_phy_sleepwalk(struct tegra_xusb_lane *lane) 16592d102148SJC Kuo { 16602d102148SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 16612d102148SJC Kuo struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl); 16622d102148SJC Kuo u32 value; 16632d102148SJC Kuo 16642d102148SJC Kuo if (!priv->regmap) 16652d102148SJC Kuo return -EOPNOTSUPP; 16662d102148SJC Kuo 16672d102148SJC Kuo /* disable the wake detection */ 16682d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG); 16692d102148SJC Kuo value &= ~UHSIC_MASTER_ENABLE; 16702d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG); 16712d102148SJC Kuo 16722d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP); 16732d102148SJC Kuo value &= ~UHSIC_LINE_WAKEUP_EN; 16742d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP); 16752d102148SJC Kuo 16762d102148SJC Kuo /* disable wake event triggers of sleepwalk logic */ 16772d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG); 16782d102148SJC Kuo value &= ~UHSIC_WAKE_VAL(~0); 16792d102148SJC Kuo value |= UHSIC_WAKE_VAL_NONE; 16802d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG); 16812d102148SJC Kuo 16822d102148SJC Kuo /* power down the line state detectors of the port */ 16832d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_USB_AO); 16842d102148SJC Kuo value |= STROBE_VAL_PD | DATA0_VAL_PD | DATA1_VAL_PD; 16852d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_USB_AO); 16862d102148SJC Kuo 16872d102148SJC Kuo /* clear alarm of the sleepwalk logic */ 16882d102148SJC Kuo value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS); 16892d102148SJC Kuo value |= UHSIC_CLR_WAKE_ALARM; 16902d102148SJC Kuo padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS); 16912d102148SJC Kuo 16922d102148SJC Kuo return 0; 16932d102148SJC Kuo } 16942d102148SJC 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, 17912d102148SJC Kuo .enable_phy_sleepwalk = tegra210_pmc_utmi_enable_phy_sleepwalk, 17922d102148SJC Kuo .disable_phy_sleepwalk = tegra210_pmc_utmi_disable_phy_sleepwalk, 17932d102148SJC Kuo .enable_phy_wake = tegra210_utmi_enable_phy_wake, 17942d102148SJC Kuo .disable_phy_wake = tegra210_utmi_disable_phy_wake, 17952d102148SJC 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; 1802*0baabcbeSJC Kuo unsigned int index = lane->index; 1803*0baabcbeSJC Kuo struct tegra_xusb_usb2_port *port; 1804*0baabcbeSJC Kuo int err; 180587d66f28SThierry Reding u32 value; 180687d66f28SThierry Reding 1807*0baabcbeSJC Kuo port = tegra_xusb_find_usb2_port(padctl, index); 1808*0baabcbeSJC Kuo if (!port) { 1809*0baabcbeSJC Kuo dev_err(&phy->dev, "no port found for USB2 lane %u\n", index); 1810*0baabcbeSJC Kuo return -ENODEV; 1811*0baabcbeSJC Kuo } 1812*0baabcbeSJC Kuo 1813*0baabcbeSJC Kuo if (port->supply && port->mode == USB_DR_MODE_HOST) { 1814*0baabcbeSJC Kuo err = regulator_enable(port->supply); 1815*0baabcbeSJC Kuo if (err) 1816*0baabcbeSJC Kuo return err; 1817*0baabcbeSJC Kuo } 1818*0baabcbeSJC Kuo 1819*0baabcbeSJC Kuo mutex_lock(&padctl->lock); 1820*0baabcbeSJC Kuo 182187d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX); 182287d66f28SThierry Reding value &= ~(XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK << 182387d66f28SThierry Reding XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT); 182487d66f28SThierry Reding value |= XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB << 182587d66f28SThierry Reding XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT; 182687d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX); 182787d66f28SThierry Reding 1828*0baabcbeSJC Kuo mutex_unlock(&padctl->lock); 1829*0baabcbeSJC Kuo 18302352fdb0SJC Kuo return 0; 183187d66f28SThierry Reding } 183287d66f28SThierry Reding 183387d66f28SThierry Reding static int tegra210_usb2_phy_exit(struct phy *phy) 183487d66f28SThierry Reding { 1835*0baabcbeSJC Kuo struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 1836*0baabcbeSJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1837*0baabcbeSJC Kuo struct tegra_xusb_usb2_port *port; 1838*0baabcbeSJC Kuo int err; 1839*0baabcbeSJC Kuo 1840*0baabcbeSJC Kuo port = tegra_xusb_find_usb2_port(padctl, lane->index); 1841*0baabcbeSJC Kuo if (!port) { 1842*0baabcbeSJC Kuo dev_err(&phy->dev, "no port found for USB2 lane %u\n", lane->index); 1843*0baabcbeSJC Kuo return -ENODEV; 1844*0baabcbeSJC Kuo } 1845*0baabcbeSJC Kuo 1846*0baabcbeSJC Kuo if (port->supply && port->mode == USB_DR_MODE_HOST) { 1847*0baabcbeSJC Kuo err = regulator_disable(port->supply); 1848*0baabcbeSJC Kuo if (err) 1849*0baabcbeSJC Kuo return err; 1850*0baabcbeSJC Kuo } 1851*0baabcbeSJC Kuo 18522352fdb0SJC Kuo return 0; 185387d66f28SThierry Reding } 185487d66f28SThierry Reding 1855de792a6dSNagarjuna Kristam static int tegra210_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl, 1856de792a6dSNagarjuna Kristam bool status) 1857de792a6dSNagarjuna Kristam { 1858de792a6dSNagarjuna Kristam u32 value; 1859de792a6dSNagarjuna Kristam 1860de792a6dSNagarjuna Kristam dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear"); 1861de792a6dSNagarjuna Kristam 1862de792a6dSNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID); 1863de792a6dSNagarjuna Kristam 1864de792a6dSNagarjuna Kristam if (status) { 1865de792a6dSNagarjuna Kristam value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON; 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 } else { 1871de792a6dSNagarjuna Kristam value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON; 1872de792a6dSNagarjuna Kristam } 1873de792a6dSNagarjuna Kristam 1874de792a6dSNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID); 1875de792a6dSNagarjuna Kristam 1876de792a6dSNagarjuna Kristam return 0; 1877de792a6dSNagarjuna Kristam } 1878de792a6dSNagarjuna Kristam 1879de792a6dSNagarjuna Kristam static int tegra210_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl, 1880de792a6dSNagarjuna Kristam bool status) 1881de792a6dSNagarjuna Kristam { 1882de792a6dSNagarjuna Kristam u32 value; 1883de792a6dSNagarjuna Kristam 1884de792a6dSNagarjuna Kristam dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear"); 1885de792a6dSNagarjuna Kristam 1886de792a6dSNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID); 1887de792a6dSNagarjuna Kristam 1888de792a6dSNagarjuna Kristam if (status) { 1889de792a6dSNagarjuna Kristam if (value & XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON) { 1890de792a6dSNagarjuna Kristam value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON; 1891de792a6dSNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID); 1892de792a6dSNagarjuna Kristam usleep_range(1000, 2000); 1893de792a6dSNagarjuna Kristam 1894de792a6dSNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID); 1895de792a6dSNagarjuna Kristam } 1896de792a6dSNagarjuna Kristam 1897de792a6dSNagarjuna Kristam value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK << 1898de792a6dSNagarjuna Kristam XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT); 1899de792a6dSNagarjuna Kristam value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED << 1900de792a6dSNagarjuna Kristam XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT; 1901de792a6dSNagarjuna Kristam } else { 1902de792a6dSNagarjuna Kristam value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK << 1903de792a6dSNagarjuna Kristam XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT); 1904de792a6dSNagarjuna Kristam value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING << 1905de792a6dSNagarjuna Kristam XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT; 1906de792a6dSNagarjuna Kristam } 1907de792a6dSNagarjuna Kristam 1908de792a6dSNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID); 1909de792a6dSNagarjuna Kristam 1910de792a6dSNagarjuna Kristam return 0; 1911de792a6dSNagarjuna Kristam } 1912de792a6dSNagarjuna Kristam 1913de792a6dSNagarjuna Kristam static int tegra210_usb2_phy_set_mode(struct phy *phy, enum phy_mode mode, 1914de792a6dSNagarjuna Kristam int submode) 1915de792a6dSNagarjuna Kristam { 1916de792a6dSNagarjuna Kristam struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 1917de792a6dSNagarjuna Kristam struct tegra_xusb_padctl *padctl = lane->pad->padctl; 1918de792a6dSNagarjuna Kristam struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl, 1919de792a6dSNagarjuna Kristam lane->index); 1920de792a6dSNagarjuna Kristam int err = 0; 1921de792a6dSNagarjuna Kristam 1922de792a6dSNagarjuna Kristam mutex_lock(&padctl->lock); 1923de792a6dSNagarjuna Kristam 1924de792a6dSNagarjuna Kristam dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode); 1925de792a6dSNagarjuna Kristam 1926de792a6dSNagarjuna Kristam if (mode == PHY_MODE_USB_OTG) { 1927de792a6dSNagarjuna Kristam if (submode == USB_ROLE_HOST) { 1928de792a6dSNagarjuna Kristam tegra210_xusb_padctl_id_override(padctl, true); 1929de792a6dSNagarjuna Kristam 1930de792a6dSNagarjuna Kristam err = regulator_enable(port->supply); 1931de792a6dSNagarjuna Kristam } else if (submode == USB_ROLE_DEVICE) { 1932de792a6dSNagarjuna Kristam tegra210_xusb_padctl_vbus_override(padctl, true); 1933de792a6dSNagarjuna Kristam } else if (submode == USB_ROLE_NONE) { 1934de792a6dSNagarjuna Kristam /* 1935de792a6dSNagarjuna Kristam * When port is peripheral only or role transitions to 1936de792a6dSNagarjuna Kristam * USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not 1937de792a6dSNagarjuna Kristam * be enabled. 1938de792a6dSNagarjuna Kristam */ 1939de792a6dSNagarjuna Kristam if (regulator_is_enabled(port->supply)) 1940de792a6dSNagarjuna Kristam regulator_disable(port->supply); 1941de792a6dSNagarjuna Kristam 1942de792a6dSNagarjuna Kristam tegra210_xusb_padctl_id_override(padctl, false); 1943de792a6dSNagarjuna Kristam tegra210_xusb_padctl_vbus_override(padctl, false); 1944de792a6dSNagarjuna Kristam } 1945de792a6dSNagarjuna Kristam } 1946de792a6dSNagarjuna Kristam 1947de792a6dSNagarjuna Kristam mutex_unlock(&padctl->lock); 1948de792a6dSNagarjuna Kristam 1949de792a6dSNagarjuna Kristam return err; 1950de792a6dSNagarjuna Kristam } 1951de792a6dSNagarjuna Kristam 195287d66f28SThierry Reding static int tegra210_usb2_phy_power_on(struct phy *phy) 195387d66f28SThierry Reding { 195487d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 195587d66f28SThierry Reding struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); 195687d66f28SThierry Reding struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad); 195787d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 195887d66f28SThierry Reding struct tegra210_xusb_padctl *priv; 195987d66f28SThierry Reding struct tegra_xusb_usb2_port *port; 196087d66f28SThierry Reding unsigned int index = lane->index; 196187d66f28SThierry Reding u32 value; 196287d66f28SThierry Reding int err; 196387d66f28SThierry Reding 196487d66f28SThierry Reding port = tegra_xusb_find_usb2_port(padctl, index); 196587d66f28SThierry Reding if (!port) { 196687d66f28SThierry Reding dev_err(&phy->dev, "no port found for USB2 lane %u\n", index); 196787d66f28SThierry Reding return -ENODEV; 196887d66f28SThierry Reding } 196987d66f28SThierry Reding 197087d66f28SThierry Reding priv = to_tegra210_xusb_padctl(padctl); 197187d66f28SThierry Reding 1972*0baabcbeSJC Kuo mutex_lock(&padctl->lock); 1973*0baabcbeSJC Kuo 1974a5be28c3SNagarjuna Kristam if (port->usb3_port_fake != -1) { 1975a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); 1976a5be28c3SNagarjuna Kristam value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK( 1977a5be28c3SNagarjuna Kristam port->usb3_port_fake); 1978a5be28c3SNagarjuna Kristam value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP( 1979a5be28c3SNagarjuna Kristam port->usb3_port_fake, index); 1980a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP); 1981a5be28c3SNagarjuna Kristam 1982a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 1983a5be28c3SNagarjuna Kristam value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN( 1984a5be28c3SNagarjuna Kristam port->usb3_port_fake); 1985a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 1986a5be28c3SNagarjuna Kristam 1987a5be28c3SNagarjuna Kristam usleep_range(100, 200); 1988a5be28c3SNagarjuna Kristam 1989a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 1990a5be28c3SNagarjuna Kristam value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY( 1991a5be28c3SNagarjuna Kristam port->usb3_port_fake); 1992a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 1993a5be28c3SNagarjuna Kristam 1994a5be28c3SNagarjuna Kristam usleep_range(100, 200); 1995a5be28c3SNagarjuna Kristam 1996a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 1997a5be28c3SNagarjuna Kristam value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN( 1998a5be28c3SNagarjuna Kristam port->usb3_port_fake); 1999a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 2000a5be28c3SNagarjuna Kristam } 2001a5be28c3SNagarjuna Kristam 200287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 200387d66f28SThierry Reding value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK << 200487d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) | 200587d66f28SThierry Reding (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK << 200687d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT)); 200787d66f28SThierry Reding value |= (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_VAL << 200887d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT); 200987d66f28SThierry Reding 201087d66f28SThierry Reding if (tegra_sku_info.revision < TEGRA_REVISION_A02) 201187d66f28SThierry Reding value |= 201287d66f28SThierry Reding (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_VAL << 201387d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT); 201487d66f28SThierry Reding 201587d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 201687d66f28SThierry Reding 201787d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP); 201887d66f28SThierry Reding value &= ~XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(index); 2019ac25b6e9SNagarjuna Kristam if (port->mode == USB_DR_MODE_UNKNOWN) 2020ac25b6e9SNagarjuna Kristam value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DISABLED(index); 2021ac25b6e9SNagarjuna Kristam else if (port->mode == USB_DR_MODE_PERIPHERAL) 2022ac25b6e9SNagarjuna Kristam value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DEVICE(index); 2023ac25b6e9SNagarjuna Kristam else if (port->mode == USB_DR_MODE_HOST) 202487d66f28SThierry Reding value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(index); 2025ac25b6e9SNagarjuna Kristam else if (port->mode == USB_DR_MODE_OTG) 2026ac25b6e9SNagarjuna Kristam value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_OTG(index); 202787d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP); 202887d66f28SThierry Reding 202987d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); 203087d66f28SThierry Reding value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK << 203187d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT) | 203287d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD | 203387d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 | 203487d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI); 203587d66f28SThierry Reding value |= (priv->fuse.hs_curr_level[index] + 203687d66f28SThierry Reding usb2->hs_curr_level_offset) << 203787d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT; 203887d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); 203987d66f28SThierry Reding 204087d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); 204187d66f28SThierry Reding value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK << 204287d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) | 204387d66f28SThierry Reding (XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_MASK << 204487d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT) | 204587d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR | 204687d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD | 204787d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD); 204887d66f28SThierry Reding value |= (priv->fuse.hs_term_range_adj << 204987d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) | 205087d66f28SThierry Reding (priv->fuse.rpd_ctrl << 205187d66f28SThierry Reding XUSB_PADCTL_USB2_OTG_PAD_CTL1_RPD_CTRL_SHIFT); 205287d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); 205387d66f28SThierry Reding 205487d66f28SThierry Reding value = padctl_readl(padctl, 205587d66f28SThierry Reding XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index)); 205687d66f28SThierry Reding value &= ~(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_MASK << 205787d66f28SThierry Reding XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT); 2058ac25b6e9SNagarjuna Kristam if (port->mode == USB_DR_MODE_HOST) 205987d66f28SThierry Reding value |= XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18; 2060ac25b6e9SNagarjuna Kristam else 2061ac25b6e9SNagarjuna Kristam value |= 2062ac25b6e9SNagarjuna Kristam XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_VAL << 2063ac25b6e9SNagarjuna Kristam XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT; 206487d66f28SThierry Reding padctl_writel(padctl, value, 206587d66f28SThierry Reding XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index)); 206687d66f28SThierry Reding 206787d66f28SThierry Reding if (pad->enable > 0) { 206887d66f28SThierry Reding pad->enable++; 206987d66f28SThierry Reding mutex_unlock(&padctl->lock); 207087d66f28SThierry Reding return 0; 207187d66f28SThierry Reding } 207287d66f28SThierry Reding 207387d66f28SThierry Reding err = clk_prepare_enable(pad->clk); 207487d66f28SThierry Reding if (err) 2075*0baabcbeSJC Kuo goto out; 207687d66f28SThierry Reding 207787d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 207887d66f28SThierry Reding value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK << 207987d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) | 208087d66f28SThierry Reding (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_MASK << 208187d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT)); 208287d66f28SThierry Reding value |= (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL << 208387d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT) | 208487d66f28SThierry Reding (XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_VAL << 208587d66f28SThierry Reding XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_DONE_RESET_TIMER_SHIFT); 208687d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 208787d66f28SThierry Reding 208887d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 208987d66f28SThierry Reding value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; 209087d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 209187d66f28SThierry Reding 209287d66f28SThierry Reding udelay(1); 209387d66f28SThierry Reding 209487d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 209587d66f28SThierry Reding value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL1_PD_TRK; 209687d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); 209787d66f28SThierry Reding 209887d66f28SThierry Reding udelay(50); 209987d66f28SThierry Reding 210087d66f28SThierry Reding clk_disable_unprepare(pad->clk); 210187d66f28SThierry Reding 210287d66f28SThierry Reding pad->enable++; 210387d66f28SThierry Reding mutex_unlock(&padctl->lock); 210487d66f28SThierry Reding 210587d66f28SThierry Reding return 0; 210687d66f28SThierry Reding 2107*0baabcbeSJC Kuo out: 210887d66f28SThierry Reding mutex_unlock(&padctl->lock); 210987d66f28SThierry Reding return err; 211087d66f28SThierry Reding } 211187d66f28SThierry Reding 211287d66f28SThierry Reding static int tegra210_usb2_phy_power_off(struct phy *phy) 211387d66f28SThierry Reding { 211487d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 211587d66f28SThierry Reding struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad); 211687d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 211787d66f28SThierry Reding struct tegra_xusb_usb2_port *port; 211887d66f28SThierry Reding u32 value; 211987d66f28SThierry Reding 212087d66f28SThierry Reding port = tegra_xusb_find_usb2_port(padctl, lane->index); 212187d66f28SThierry Reding if (!port) { 212287d66f28SThierry Reding dev_err(&phy->dev, "no port found for USB2 lane %u\n", 212387d66f28SThierry Reding lane->index); 212487d66f28SThierry Reding return -ENODEV; 212587d66f28SThierry Reding } 212687d66f28SThierry Reding 212787d66f28SThierry Reding mutex_lock(&padctl->lock); 212887d66f28SThierry Reding 2129a5be28c3SNagarjuna Kristam if (port->usb3_port_fake != -1) { 2130a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 2131a5be28c3SNagarjuna Kristam value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY( 2132a5be28c3SNagarjuna Kristam port->usb3_port_fake); 2133a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 2134a5be28c3SNagarjuna Kristam 2135a5be28c3SNagarjuna Kristam usleep_range(100, 200); 2136a5be28c3SNagarjuna Kristam 2137a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 2138a5be28c3SNagarjuna Kristam value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN( 2139a5be28c3SNagarjuna Kristam port->usb3_port_fake); 2140a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 2141a5be28c3SNagarjuna Kristam 2142a5be28c3SNagarjuna Kristam usleep_range(250, 350); 2143a5be28c3SNagarjuna Kristam 2144a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 2145a5be28c3SNagarjuna Kristam value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN( 2146a5be28c3SNagarjuna Kristam port->usb3_port_fake); 2147a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 2148a5be28c3SNagarjuna Kristam 2149a5be28c3SNagarjuna Kristam value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); 2150a5be28c3SNagarjuna Kristam value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(port->usb3_port_fake, 2151a5be28c3SNagarjuna Kristam XUSB_PADCTL_SS_PORT_MAP_PORT_DISABLED); 2152a5be28c3SNagarjuna Kristam padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP); 2153a5be28c3SNagarjuna Kristam } 2154a5be28c3SNagarjuna Kristam 215587d66f28SThierry Reding if (WARN_ON(pad->enable == 0)) 215687d66f28SThierry Reding goto out; 215787d66f28SThierry Reding 215887d66f28SThierry Reding if (--pad->enable > 0) 215987d66f28SThierry Reding goto out; 216087d66f28SThierry Reding 216187d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 216287d66f28SThierry Reding value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; 216387d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 216487d66f28SThierry Reding 216587d66f28SThierry Reding out: 216687d66f28SThierry Reding mutex_unlock(&padctl->lock); 216787d66f28SThierry Reding return 0; 216887d66f28SThierry Reding } 216987d66f28SThierry Reding 217087d66f28SThierry Reding static const struct phy_ops tegra210_usb2_phy_ops = { 217187d66f28SThierry Reding .init = tegra210_usb2_phy_init, 217287d66f28SThierry Reding .exit = tegra210_usb2_phy_exit, 217387d66f28SThierry Reding .power_on = tegra210_usb2_phy_power_on, 217487d66f28SThierry Reding .power_off = tegra210_usb2_phy_power_off, 2175de792a6dSNagarjuna Kristam .set_mode = tegra210_usb2_phy_set_mode, 217687d66f28SThierry Reding .owner = THIS_MODULE, 217787d66f28SThierry Reding }; 217887d66f28SThierry Reding 217987d66f28SThierry Reding static struct tegra_xusb_pad * 218087d66f28SThierry Reding tegra210_usb2_pad_probe(struct tegra_xusb_padctl *padctl, 218187d66f28SThierry Reding const struct tegra_xusb_pad_soc *soc, 218287d66f28SThierry Reding struct device_node *np) 218387d66f28SThierry Reding { 218487d66f28SThierry Reding struct tegra_xusb_usb2_pad *usb2; 218587d66f28SThierry Reding struct tegra_xusb_pad *pad; 218687d66f28SThierry Reding int err; 218787d66f28SThierry Reding 218887d66f28SThierry Reding usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL); 218987d66f28SThierry Reding if (!usb2) 219087d66f28SThierry Reding return ERR_PTR(-ENOMEM); 219187d66f28SThierry Reding 219287d66f28SThierry Reding pad = &usb2->base; 219387d66f28SThierry Reding pad->ops = &tegra210_usb2_lane_ops; 219487d66f28SThierry Reding pad->soc = soc; 219587d66f28SThierry Reding 219687d66f28SThierry Reding err = tegra_xusb_pad_init(pad, padctl, np); 219787d66f28SThierry Reding if (err < 0) { 219887d66f28SThierry Reding kfree(usb2); 219987d66f28SThierry Reding goto out; 220087d66f28SThierry Reding } 220187d66f28SThierry Reding 220287d66f28SThierry Reding usb2->clk = devm_clk_get(&pad->dev, "trk"); 220387d66f28SThierry Reding if (IS_ERR(usb2->clk)) { 220487d66f28SThierry Reding err = PTR_ERR(usb2->clk); 220587d66f28SThierry Reding dev_err(&pad->dev, "failed to get trk clock: %d\n", err); 220687d66f28SThierry Reding goto unregister; 220787d66f28SThierry Reding } 220887d66f28SThierry Reding 220987d66f28SThierry Reding err = tegra_xusb_pad_register(pad, &tegra210_usb2_phy_ops); 221087d66f28SThierry Reding if (err < 0) 221187d66f28SThierry Reding goto unregister; 221287d66f28SThierry Reding 221387d66f28SThierry Reding dev_set_drvdata(&pad->dev, pad); 221487d66f28SThierry Reding 221587d66f28SThierry Reding return pad; 221687d66f28SThierry Reding 221787d66f28SThierry Reding unregister: 221887d66f28SThierry Reding device_unregister(&pad->dev); 221987d66f28SThierry Reding out: 222087d66f28SThierry Reding return ERR_PTR(err); 222187d66f28SThierry Reding } 222287d66f28SThierry Reding 222387d66f28SThierry Reding static void tegra210_usb2_pad_remove(struct tegra_xusb_pad *pad) 222487d66f28SThierry Reding { 222587d66f28SThierry Reding struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad); 222687d66f28SThierry Reding 222787d66f28SThierry Reding kfree(usb2); 222887d66f28SThierry Reding } 222987d66f28SThierry Reding 223087d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_usb2_ops = { 223187d66f28SThierry Reding .probe = tegra210_usb2_pad_probe, 223287d66f28SThierry Reding .remove = tegra210_usb2_pad_remove, 223387d66f28SThierry Reding }; 223487d66f28SThierry Reding 223587d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_usb2_pad = { 223687d66f28SThierry Reding .name = "usb2", 223787d66f28SThierry Reding .num_lanes = ARRAY_SIZE(tegra210_usb2_lanes), 223887d66f28SThierry Reding .lanes = tegra210_usb2_lanes, 223987d66f28SThierry Reding .ops = &tegra210_usb2_ops, 224087d66f28SThierry Reding }; 224187d66f28SThierry Reding 224287d66f28SThierry Reding static const char *tegra210_hsic_functions[] = { 224387d66f28SThierry Reding "snps", 224487d66f28SThierry Reding "xusb", 224587d66f28SThierry Reding }; 224687d66f28SThierry Reding 224787d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_hsic_lanes[] = { 224887d66f28SThierry Reding TEGRA210_LANE("hsic-0", 0x004, 14, 0x1, hsic), 224987d66f28SThierry Reding }; 225087d66f28SThierry Reding 225187d66f28SThierry Reding static struct tegra_xusb_lane * 225287d66f28SThierry Reding tegra210_hsic_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, 225387d66f28SThierry Reding unsigned int index) 225487d66f28SThierry Reding { 225587d66f28SThierry Reding struct tegra_xusb_hsic_lane *hsic; 225687d66f28SThierry Reding int err; 225787d66f28SThierry Reding 225887d66f28SThierry Reding hsic = kzalloc(sizeof(*hsic), GFP_KERNEL); 225987d66f28SThierry Reding if (!hsic) 226087d66f28SThierry Reding return ERR_PTR(-ENOMEM); 226187d66f28SThierry Reding 226287d66f28SThierry Reding INIT_LIST_HEAD(&hsic->base.list); 226387d66f28SThierry Reding hsic->base.soc = &pad->soc->lanes[index]; 226487d66f28SThierry Reding hsic->base.index = index; 226587d66f28SThierry Reding hsic->base.pad = pad; 226687d66f28SThierry Reding hsic->base.np = np; 226787d66f28SThierry Reding 226887d66f28SThierry Reding err = tegra_xusb_lane_parse_dt(&hsic->base, np); 226987d66f28SThierry Reding if (err < 0) { 227087d66f28SThierry Reding kfree(hsic); 227187d66f28SThierry Reding return ERR_PTR(err); 227287d66f28SThierry Reding } 227387d66f28SThierry Reding 227487d66f28SThierry Reding return &hsic->base; 227587d66f28SThierry Reding } 227687d66f28SThierry Reding 227787d66f28SThierry Reding static void tegra210_hsic_lane_remove(struct tegra_xusb_lane *lane) 227887d66f28SThierry Reding { 227987d66f28SThierry Reding struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane); 228087d66f28SThierry Reding 228187d66f28SThierry Reding kfree(hsic); 228287d66f28SThierry Reding } 228387d66f28SThierry Reding 228487d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_hsic_lane_ops = { 228587d66f28SThierry Reding .probe = tegra210_hsic_lane_probe, 228687d66f28SThierry Reding .remove = tegra210_hsic_lane_remove, 22872d102148SJC Kuo .enable_phy_sleepwalk = tegra210_pmc_hsic_enable_phy_sleepwalk, 22882d102148SJC Kuo .disable_phy_sleepwalk = tegra210_pmc_hsic_disable_phy_sleepwalk, 22892d102148SJC Kuo .enable_phy_wake = tegra210_hsic_enable_phy_wake, 22902d102148SJC Kuo .disable_phy_wake = tegra210_hsic_disable_phy_wake, 22912d102148SJC Kuo .remote_wake_detected = tegra210_hsic_phy_remote_wake_detected, 229287d66f28SThierry Reding }; 229387d66f28SThierry Reding 229487d66f28SThierry Reding static int tegra210_hsic_phy_init(struct phy *phy) 229587d66f28SThierry Reding { 229687d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 229787d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 229887d66f28SThierry Reding u32 value; 229987d66f28SThierry Reding 230087d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX); 230187d66f28SThierry Reding value &= ~(XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_MASK << 230287d66f28SThierry Reding XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT); 230387d66f28SThierry Reding value |= XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_XUSB << 230487d66f28SThierry Reding XUSB_PADCTL_USB2_PAD_MUX_HSIC_PAD_TRK_SHIFT; 230587d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX); 230687d66f28SThierry Reding 23072352fdb0SJC Kuo return 0; 230887d66f28SThierry Reding } 230987d66f28SThierry Reding 231087d66f28SThierry Reding static int tegra210_hsic_phy_exit(struct phy *phy) 231187d66f28SThierry Reding { 23122352fdb0SJC Kuo return 0; 231387d66f28SThierry Reding } 231487d66f28SThierry Reding 231587d66f28SThierry Reding static int tegra210_hsic_phy_power_on(struct phy *phy) 231687d66f28SThierry Reding { 231787d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 231887d66f28SThierry Reding struct tegra_xusb_hsic_lane *hsic = to_hsic_lane(lane); 231987d66f28SThierry Reding struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad); 232087d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 232187d66f28SThierry Reding unsigned int index = lane->index; 232287d66f28SThierry Reding u32 value; 232387d66f28SThierry Reding int err; 232487d66f28SThierry Reding 232587d66f28SThierry Reding err = regulator_enable(pad->supply); 232687d66f28SThierry Reding if (err) 232787d66f28SThierry Reding return err; 232887d66f28SThierry Reding 232987d66f28SThierry Reding padctl_writel(padctl, hsic->strobe_trim, 233087d66f28SThierry Reding XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL); 233187d66f28SThierry Reding 233287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(index)); 233387d66f28SThierry Reding value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_MASK << 233487d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT); 233587d66f28SThierry Reding value |= (hsic->tx_rtune_p << 233687d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL1_TX_RTUNEP_SHIFT); 233787d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index)); 233887d66f28SThierry Reding 233987d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(index)); 234087d66f28SThierry Reding value &= ~((XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK << 234187d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) | 234287d66f28SThierry Reding (XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK << 234387d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT)); 234487d66f28SThierry Reding value |= (hsic->rx_strobe_trim << 234587d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT) | 234687d66f28SThierry Reding (hsic->rx_data_trim << 234787d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT); 234887d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL2(index)); 234987d66f28SThierry Reding 235087d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index)); 235187d66f28SThierry Reding value &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA0 | 235287d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_RPU_DATA1 | 235387d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE | 235487d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 | 235587d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 | 235687d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE | 235787d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 | 235887d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 | 235987d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE | 236087d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 | 236187d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 | 236287d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE); 236387d66f28SThierry Reding value |= XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA0 | 236487d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_RPD_DATA1 | 236587d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_RPD_STROBE; 236687d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL0(index)); 236787d66f28SThierry Reding 236887d66f28SThierry Reding err = clk_prepare_enable(pad->clk); 236987d66f28SThierry Reding if (err) 237087d66f28SThierry Reding goto disable; 237187d66f28SThierry Reding 237287d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PAD_TRK_CTL); 237387d66f28SThierry Reding value &= ~((XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_MASK << 237487d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT) | 237587d66f28SThierry Reding (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_MASK << 237687d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT)); 237787d66f28SThierry Reding value |= (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_VAL << 237887d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_START_TIMER_SHIFT) | 237987d66f28SThierry Reding (XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_VAL << 238087d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_TRK_CTL_TRK_DONE_RESET_TIMER_SHIFT); 238187d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PAD_TRK_CTL); 238287d66f28SThierry Reding 238387d66f28SThierry Reding udelay(1); 238487d66f28SThierry Reding 238587d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PAD_TRK_CTL); 238687d66f28SThierry Reding value &= ~XUSB_PADCTL_HSIC_PAD_TRK_CTL_PD_TRK; 238787d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PAD_TRK_CTL); 238887d66f28SThierry Reding 238987d66f28SThierry Reding udelay(50); 239087d66f28SThierry Reding 239187d66f28SThierry Reding clk_disable_unprepare(pad->clk); 239287d66f28SThierry Reding 239387d66f28SThierry Reding return 0; 239487d66f28SThierry Reding 239587d66f28SThierry Reding disable: 239687d66f28SThierry Reding regulator_disable(pad->supply); 239787d66f28SThierry Reding return err; 239887d66f28SThierry Reding } 239987d66f28SThierry Reding 240087d66f28SThierry Reding static int tegra210_hsic_phy_power_off(struct phy *phy) 240187d66f28SThierry Reding { 240287d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 240387d66f28SThierry Reding struct tegra_xusb_hsic_pad *pad = to_hsic_pad(lane->pad); 240487d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 240587d66f28SThierry Reding unsigned int index = lane->index; 240687d66f28SThierry Reding u32 value; 240787d66f28SThierry Reding 240887d66f28SThierry Reding value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(index)); 240987d66f28SThierry Reding value |= XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA0 | 241087d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_DATA1 | 241187d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_RX_STROBE | 241287d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA0 | 241387d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_DATA1 | 241487d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_ZI_STROBE | 241587d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA0 | 241687d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_DATA1 | 241787d66f28SThierry Reding XUSB_PADCTL_HSIC_PAD_CTL0_PD_TX_STROBE; 241887d66f28SThierry Reding padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(index)); 241987d66f28SThierry Reding 242087d66f28SThierry Reding regulator_disable(pad->supply); 242187d66f28SThierry Reding 242287d66f28SThierry Reding return 0; 242387d66f28SThierry Reding } 242487d66f28SThierry Reding 242587d66f28SThierry Reding static const struct phy_ops tegra210_hsic_phy_ops = { 242687d66f28SThierry Reding .init = tegra210_hsic_phy_init, 242787d66f28SThierry Reding .exit = tegra210_hsic_phy_exit, 242887d66f28SThierry Reding .power_on = tegra210_hsic_phy_power_on, 242987d66f28SThierry Reding .power_off = tegra210_hsic_phy_power_off, 243087d66f28SThierry Reding .owner = THIS_MODULE, 243187d66f28SThierry Reding }; 243287d66f28SThierry Reding 243387d66f28SThierry Reding static struct tegra_xusb_pad * 243487d66f28SThierry Reding tegra210_hsic_pad_probe(struct tegra_xusb_padctl *padctl, 243587d66f28SThierry Reding const struct tegra_xusb_pad_soc *soc, 243687d66f28SThierry Reding struct device_node *np) 243787d66f28SThierry Reding { 243887d66f28SThierry Reding struct tegra_xusb_hsic_pad *hsic; 243987d66f28SThierry Reding struct tegra_xusb_pad *pad; 244087d66f28SThierry Reding int err; 244187d66f28SThierry Reding 244287d66f28SThierry Reding hsic = kzalloc(sizeof(*hsic), GFP_KERNEL); 244387d66f28SThierry Reding if (!hsic) 244487d66f28SThierry Reding return ERR_PTR(-ENOMEM); 244587d66f28SThierry Reding 244687d66f28SThierry Reding pad = &hsic->base; 244787d66f28SThierry Reding pad->ops = &tegra210_hsic_lane_ops; 244887d66f28SThierry Reding pad->soc = soc; 244987d66f28SThierry Reding 245087d66f28SThierry Reding err = tegra_xusb_pad_init(pad, padctl, np); 245187d66f28SThierry Reding if (err < 0) { 245287d66f28SThierry Reding kfree(hsic); 245387d66f28SThierry Reding goto out; 245487d66f28SThierry Reding } 245587d66f28SThierry Reding 245687d66f28SThierry Reding hsic->clk = devm_clk_get(&pad->dev, "trk"); 245787d66f28SThierry Reding if (IS_ERR(hsic->clk)) { 245887d66f28SThierry Reding err = PTR_ERR(hsic->clk); 245987d66f28SThierry Reding dev_err(&pad->dev, "failed to get trk clock: %d\n", err); 246087d66f28SThierry Reding goto unregister; 246187d66f28SThierry Reding } 246287d66f28SThierry Reding 246387d66f28SThierry Reding err = tegra_xusb_pad_register(pad, &tegra210_hsic_phy_ops); 246487d66f28SThierry Reding if (err < 0) 246587d66f28SThierry Reding goto unregister; 246687d66f28SThierry Reding 246787d66f28SThierry Reding dev_set_drvdata(&pad->dev, pad); 246887d66f28SThierry Reding 246987d66f28SThierry Reding return pad; 247087d66f28SThierry Reding 247187d66f28SThierry Reding unregister: 247287d66f28SThierry Reding device_unregister(&pad->dev); 247387d66f28SThierry Reding out: 247487d66f28SThierry Reding return ERR_PTR(err); 247587d66f28SThierry Reding } 247687d66f28SThierry Reding 247787d66f28SThierry Reding static void tegra210_hsic_pad_remove(struct tegra_xusb_pad *pad) 247887d66f28SThierry Reding { 247987d66f28SThierry Reding struct tegra_xusb_hsic_pad *hsic = to_hsic_pad(pad); 248087d66f28SThierry Reding 248187d66f28SThierry Reding kfree(hsic); 248287d66f28SThierry Reding } 248387d66f28SThierry Reding 248487d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_hsic_ops = { 248587d66f28SThierry Reding .probe = tegra210_hsic_pad_probe, 248687d66f28SThierry Reding .remove = tegra210_hsic_pad_remove, 248787d66f28SThierry Reding }; 248887d66f28SThierry Reding 248987d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_hsic_pad = { 249087d66f28SThierry Reding .name = "hsic", 249187d66f28SThierry Reding .num_lanes = ARRAY_SIZE(tegra210_hsic_lanes), 249287d66f28SThierry Reding .lanes = tegra210_hsic_lanes, 249387d66f28SThierry Reding .ops = &tegra210_hsic_ops, 249487d66f28SThierry Reding }; 249587d66f28SThierry Reding 2496c339605cSJC Kuo static void tegra210_uphy_lane_iddq_enable(struct tegra_xusb_lane *lane) 2497c339605cSJC Kuo { 2498c339605cSJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 2499c339605cSJC Kuo u32 value; 2500c339605cSJC Kuo 2501c339605cSJC Kuo value = padctl_readl(padctl, lane->soc->regs.misc_ctl2); 2502c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD; 2503c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD; 2504c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD; 2505c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD; 2506c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ; 2507c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK; 2508c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL; 2509c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ; 2510c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK; 2511c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL; 2512c339605cSJC Kuo padctl_writel(padctl, value, lane->soc->regs.misc_ctl2); 2513c339605cSJC Kuo } 2514c339605cSJC Kuo 2515c339605cSJC Kuo static void tegra210_uphy_lane_iddq_disable(struct tegra_xusb_lane *lane) 2516c339605cSJC Kuo { 2517c339605cSJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 2518c339605cSJC Kuo u32 value; 2519c339605cSJC Kuo 2520c339605cSJC Kuo value = padctl_readl(padctl, lane->soc->regs.misc_ctl2); 2521c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD; 2522c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD; 2523c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD; 2524c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD; 2525c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ; 2526c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK; 2527c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL; 2528c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ; 2529c339605cSJC Kuo value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK; 2530c339605cSJC Kuo value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL; 2531c339605cSJC Kuo padctl_writel(padctl, value, lane->soc->regs.misc_ctl2); 2532c339605cSJC Kuo } 2533c339605cSJC Kuo 2534c339605cSJC Kuo #define TEGRA210_UPHY_LANE(_name, _offset, _shift, _mask, _type, _misc) \ 2535c339605cSJC Kuo { \ 2536c339605cSJC Kuo .name = _name, \ 2537c339605cSJC Kuo .offset = _offset, \ 2538c339605cSJC Kuo .shift = _shift, \ 2539c339605cSJC Kuo .mask = _mask, \ 2540c339605cSJC Kuo .num_funcs = ARRAY_SIZE(tegra210_##_type##_functions), \ 2541c339605cSJC Kuo .funcs = tegra210_##_type##_functions, \ 2542c339605cSJC Kuo .regs.misc_ctl2 = _misc, \ 2543c339605cSJC Kuo } 2544c339605cSJC Kuo 254587d66f28SThierry Reding static const char *tegra210_pcie_functions[] = { 254687d66f28SThierry Reding "pcie-x1", 254787d66f28SThierry Reding "usb3-ss", 254887d66f28SThierry Reding "sata", 254987d66f28SThierry Reding "pcie-x4", 255087d66f28SThierry Reding }; 255187d66f28SThierry Reding 255287d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_pcie_lanes[] = { 2553c339605cSJC Kuo TEGRA210_UPHY_LANE("pcie-0", 0x028, 12, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)), 2554c339605cSJC Kuo TEGRA210_UPHY_LANE("pcie-1", 0x028, 14, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(1)), 2555c339605cSJC Kuo TEGRA210_UPHY_LANE("pcie-2", 0x028, 16, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(2)), 2556c339605cSJC Kuo TEGRA210_UPHY_LANE("pcie-3", 0x028, 18, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(3)), 2557c339605cSJC Kuo TEGRA210_UPHY_LANE("pcie-4", 0x028, 20, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(4)), 2558c339605cSJC Kuo TEGRA210_UPHY_LANE("pcie-5", 0x028, 22, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(5)), 2559c339605cSJC Kuo TEGRA210_UPHY_LANE("pcie-6", 0x028, 24, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(6)), 256087d66f28SThierry Reding }; 256187d66f28SThierry Reding 256223d5ec3fSJC Kuo static struct tegra_xusb_usb3_port * 256323d5ec3fSJC Kuo tegra210_lane_to_usb3_port(struct tegra_xusb_lane *lane) 256423d5ec3fSJC Kuo { 256523d5ec3fSJC Kuo int port; 256623d5ec3fSJC Kuo 256723d5ec3fSJC Kuo if (!lane || !lane->pad || !lane->pad->padctl) 256823d5ec3fSJC Kuo return NULL; 256923d5ec3fSJC Kuo 257023d5ec3fSJC Kuo port = tegra210_usb3_lane_map(lane); 257123d5ec3fSJC Kuo if (port < 0) 257223d5ec3fSJC Kuo return NULL; 257323d5ec3fSJC Kuo 257423d5ec3fSJC Kuo return tegra_xusb_find_usb3_port(lane->pad->padctl, port); 257523d5ec3fSJC Kuo } 257623d5ec3fSJC Kuo 257723d5ec3fSJC Kuo static int tegra210_usb3_phy_power_on(struct phy *phy) 257823d5ec3fSJC Kuo { 257923d5ec3fSJC Kuo struct device *dev = &phy->dev; 258023d5ec3fSJC Kuo struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 258123d5ec3fSJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 258223d5ec3fSJC Kuo struct tegra_xusb_usb3_port *usb3 = tegra210_lane_to_usb3_port(lane); 258323d5ec3fSJC Kuo unsigned int index; 258423d5ec3fSJC Kuo u32 value; 258523d5ec3fSJC Kuo 258623d5ec3fSJC Kuo if (!usb3) { 258723d5ec3fSJC Kuo dev_err(dev, "no USB3 port found for lane %u\n", lane->index); 258823d5ec3fSJC Kuo return -ENODEV; 258923d5ec3fSJC Kuo } 259023d5ec3fSJC Kuo 259123d5ec3fSJC Kuo index = usb3->base.index; 259223d5ec3fSJC Kuo 259323d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); 259423d5ec3fSJC Kuo 259523d5ec3fSJC Kuo if (!usb3->internal) 259623d5ec3fSJC Kuo value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index); 259723d5ec3fSJC Kuo else 259823d5ec3fSJC Kuo value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_INTERNAL(index); 259923d5ec3fSJC Kuo 260023d5ec3fSJC Kuo value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(index); 260123d5ec3fSJC Kuo value |= XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(index, usb3->port); 260223d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_MAP); 260323d5ec3fSJC Kuo 260423d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index)); 260523d5ec3fSJC Kuo value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_MASK << 260623d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT); 260723d5ec3fSJC Kuo value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_VAL << 260823d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT; 260923d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(index)); 261023d5ec3fSJC Kuo 261123d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index)); 261223d5ec3fSJC Kuo value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_MASK << 261323d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT); 261423d5ec3fSJC Kuo value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_VAL << 261523d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PAD_ECTL2_RX_CTLE_SHIFT; 261623d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL2(index)); 261723d5ec3fSJC Kuo 261823d5ec3fSJC Kuo padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL3_RX_DFE_VAL, 261923d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PADX_ECTL3(index)); 262023d5ec3fSJC Kuo 262123d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index)); 262223d5ec3fSJC Kuo value &= ~(XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_MASK << 262323d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT); 262423d5ec3fSJC Kuo value |= XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_VAL << 262523d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PAD_ECTL4_RX_CDR_CTRL_SHIFT; 262623d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_UPHY_USB3_PADX_ECTL4(index)); 262723d5ec3fSJC Kuo 262823d5ec3fSJC Kuo padctl_writel(padctl, XUSB_PADCTL_UPHY_USB3_PAD_ECTL6_RX_EQ_CTRL_H_VAL, 262923d5ec3fSJC Kuo XUSB_PADCTL_UPHY_USB3_PADX_ECTL6(index)); 263023d5ec3fSJC Kuo 263123d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 263223d5ec3fSJC Kuo value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index); 263323d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 263423d5ec3fSJC Kuo 263523d5ec3fSJC Kuo usleep_range(100, 200); 263623d5ec3fSJC Kuo 263723d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 263823d5ec3fSJC Kuo value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index); 263923d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 264023d5ec3fSJC Kuo 264123d5ec3fSJC Kuo usleep_range(100, 200); 264223d5ec3fSJC Kuo 264323d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 264423d5ec3fSJC Kuo value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index); 264523d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 264623d5ec3fSJC Kuo 264723d5ec3fSJC Kuo return 0; 264823d5ec3fSJC Kuo } 264923d5ec3fSJC Kuo 265023d5ec3fSJC Kuo static int tegra210_usb3_phy_power_off(struct phy *phy) 265123d5ec3fSJC Kuo { 265223d5ec3fSJC Kuo struct device *dev = &phy->dev; 265323d5ec3fSJC Kuo struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 265423d5ec3fSJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 265523d5ec3fSJC Kuo struct tegra_xusb_usb3_port *usb3 = tegra210_lane_to_usb3_port(lane); 265623d5ec3fSJC Kuo unsigned int index; 265723d5ec3fSJC Kuo u32 value; 265823d5ec3fSJC Kuo 265923d5ec3fSJC Kuo if (!usb3) { 266023d5ec3fSJC Kuo dev_err(dev, "no USB3 port found for lane %u\n", lane->index); 266123d5ec3fSJC Kuo return -ENODEV; 266223d5ec3fSJC Kuo } 266323d5ec3fSJC Kuo 266423d5ec3fSJC Kuo index = usb3->base.index; 266523d5ec3fSJC Kuo 266623d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 266723d5ec3fSJC Kuo value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(index); 266823d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 266923d5ec3fSJC Kuo 267023d5ec3fSJC Kuo usleep_range(100, 200); 267123d5ec3fSJC Kuo 267223d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 267323d5ec3fSJC Kuo value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(index); 267423d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 267523d5ec3fSJC Kuo 267623d5ec3fSJC Kuo usleep_range(250, 350); 267723d5ec3fSJC Kuo 267823d5ec3fSJC Kuo value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1); 267923d5ec3fSJC Kuo value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_VCORE_DOWN(index); 268023d5ec3fSJC Kuo padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1); 268123d5ec3fSJC Kuo 268223d5ec3fSJC Kuo return 0; 268323d5ec3fSJC Kuo } 268487d66f28SThierry Reding static struct tegra_xusb_lane * 268587d66f28SThierry Reding tegra210_pcie_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, 268687d66f28SThierry Reding unsigned int index) 268787d66f28SThierry Reding { 268887d66f28SThierry Reding struct tegra_xusb_pcie_lane *pcie; 268987d66f28SThierry Reding int err; 269087d66f28SThierry Reding 269187d66f28SThierry Reding pcie = kzalloc(sizeof(*pcie), GFP_KERNEL); 269287d66f28SThierry Reding if (!pcie) 269387d66f28SThierry Reding return ERR_PTR(-ENOMEM); 269487d66f28SThierry Reding 269587d66f28SThierry Reding INIT_LIST_HEAD(&pcie->base.list); 269687d66f28SThierry Reding pcie->base.soc = &pad->soc->lanes[index]; 269787d66f28SThierry Reding pcie->base.index = index; 269887d66f28SThierry Reding pcie->base.pad = pad; 269987d66f28SThierry Reding pcie->base.np = np; 270087d66f28SThierry Reding 270187d66f28SThierry Reding err = tegra_xusb_lane_parse_dt(&pcie->base, np); 270287d66f28SThierry Reding if (err < 0) { 270387d66f28SThierry Reding kfree(pcie); 270487d66f28SThierry Reding return ERR_PTR(err); 270587d66f28SThierry Reding } 270687d66f28SThierry Reding 270787d66f28SThierry Reding return &pcie->base; 270887d66f28SThierry Reding } 270987d66f28SThierry Reding 271087d66f28SThierry Reding static void tegra210_pcie_lane_remove(struct tegra_xusb_lane *lane) 271187d66f28SThierry Reding { 271287d66f28SThierry Reding struct tegra_xusb_pcie_lane *pcie = to_pcie_lane(lane); 271387d66f28SThierry Reding 271487d66f28SThierry Reding kfree(pcie); 271587d66f28SThierry Reding } 271687d66f28SThierry Reding 271787d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_pcie_lane_ops = { 271887d66f28SThierry Reding .probe = tegra210_pcie_lane_probe, 271987d66f28SThierry Reding .remove = tegra210_pcie_lane_remove, 2720c339605cSJC Kuo .iddq_enable = tegra210_uphy_lane_iddq_enable, 2721c339605cSJC Kuo .iddq_disable = tegra210_uphy_lane_iddq_disable, 27222d102148SJC Kuo .enable_phy_sleepwalk = tegra210_usb3_enable_phy_sleepwalk, 27232d102148SJC Kuo .disable_phy_sleepwalk = tegra210_usb3_disable_phy_sleepwalk, 27242d102148SJC Kuo .enable_phy_wake = tegra210_usb3_enable_phy_wake, 27252d102148SJC Kuo .disable_phy_wake = tegra210_usb3_disable_phy_wake, 27262d102148SJC Kuo .remote_wake_detected = tegra210_usb3_phy_remote_wake_detected, 272787d66f28SThierry Reding }; 272887d66f28SThierry Reding 272987d66f28SThierry Reding static int tegra210_pcie_phy_init(struct phy *phy) 273087d66f28SThierry Reding { 273187d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 27322352fdb0SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 273387d66f28SThierry Reding 27342352fdb0SJC Kuo mutex_lock(&padctl->lock); 273587d66f28SThierry Reding 27362352fdb0SJC Kuo tegra210_uphy_init(padctl); 273787d66f28SThierry Reding 27382352fdb0SJC Kuo mutex_unlock(&padctl->lock); 27392352fdb0SJC Kuo 27402352fdb0SJC Kuo return 0; 274187d66f28SThierry Reding } 274287d66f28SThierry Reding 274387d66f28SThierry Reding static int tegra210_pcie_phy_power_on(struct phy *phy) 274487d66f28SThierry Reding { 274587d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 274687d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 27472352fdb0SJC Kuo int err = 0; 274887d66f28SThierry Reding 274987d66f28SThierry Reding mutex_lock(&padctl->lock); 275087d66f28SThierry Reding 275123d5ec3fSJC Kuo if (tegra_xusb_lane_check(lane, "usb3-ss")) 275223d5ec3fSJC Kuo err = tegra210_usb3_phy_power_on(phy); 275323d5ec3fSJC Kuo 275487d66f28SThierry Reding mutex_unlock(&padctl->lock); 275587d66f28SThierry Reding return err; 275687d66f28SThierry Reding } 275787d66f28SThierry Reding 275887d66f28SThierry Reding static int tegra210_pcie_phy_power_off(struct phy *phy) 275987d66f28SThierry Reding { 276087d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 276187d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 276223d5ec3fSJC Kuo int err = 0; 276387d66f28SThierry Reding 276423d5ec3fSJC Kuo mutex_lock(&padctl->lock); 276523d5ec3fSJC Kuo 276623d5ec3fSJC Kuo if (tegra_xusb_lane_check(lane, "usb3-ss")) 276723d5ec3fSJC Kuo err = tegra210_usb3_phy_power_off(phy); 276823d5ec3fSJC Kuo 276923d5ec3fSJC Kuo mutex_unlock(&padctl->lock); 277023d5ec3fSJC Kuo return err; 277187d66f28SThierry Reding } 277287d66f28SThierry Reding 277387d66f28SThierry Reding static const struct phy_ops tegra210_pcie_phy_ops = { 277487d66f28SThierry Reding .init = tegra210_pcie_phy_init, 277587d66f28SThierry Reding .power_on = tegra210_pcie_phy_power_on, 277687d66f28SThierry Reding .power_off = tegra210_pcie_phy_power_off, 277787d66f28SThierry Reding .owner = THIS_MODULE, 277887d66f28SThierry Reding }; 277987d66f28SThierry Reding 278087d66f28SThierry Reding static struct tegra_xusb_pad * 278187d66f28SThierry Reding tegra210_pcie_pad_probe(struct tegra_xusb_padctl *padctl, 278287d66f28SThierry Reding const struct tegra_xusb_pad_soc *soc, 278387d66f28SThierry Reding struct device_node *np) 278487d66f28SThierry Reding { 278587d66f28SThierry Reding struct tegra_xusb_pcie_pad *pcie; 278687d66f28SThierry Reding struct tegra_xusb_pad *pad; 278787d66f28SThierry Reding int err; 278887d66f28SThierry Reding 278987d66f28SThierry Reding pcie = kzalloc(sizeof(*pcie), GFP_KERNEL); 279087d66f28SThierry Reding if (!pcie) 279187d66f28SThierry Reding return ERR_PTR(-ENOMEM); 279287d66f28SThierry Reding 279387d66f28SThierry Reding pad = &pcie->base; 279487d66f28SThierry Reding pad->ops = &tegra210_pcie_lane_ops; 279587d66f28SThierry Reding pad->soc = soc; 279687d66f28SThierry Reding 279787d66f28SThierry Reding err = tegra_xusb_pad_init(pad, padctl, np); 279887d66f28SThierry Reding if (err < 0) { 279987d66f28SThierry Reding kfree(pcie); 280087d66f28SThierry Reding goto out; 280187d66f28SThierry Reding } 280287d66f28SThierry Reding 280387d66f28SThierry Reding pcie->pll = devm_clk_get(&pad->dev, "pll"); 280487d66f28SThierry Reding if (IS_ERR(pcie->pll)) { 280587d66f28SThierry Reding err = PTR_ERR(pcie->pll); 280687d66f28SThierry Reding dev_err(&pad->dev, "failed to get PLL: %d\n", err); 280787d66f28SThierry Reding goto unregister; 280887d66f28SThierry Reding } 280987d66f28SThierry Reding 281087d66f28SThierry Reding pcie->rst = devm_reset_control_get(&pad->dev, "phy"); 281187d66f28SThierry Reding if (IS_ERR(pcie->rst)) { 281287d66f28SThierry Reding err = PTR_ERR(pcie->rst); 281387d66f28SThierry Reding dev_err(&pad->dev, "failed to get PCIe pad reset: %d\n", err); 281487d66f28SThierry Reding goto unregister; 281587d66f28SThierry Reding } 281687d66f28SThierry Reding 281787d66f28SThierry Reding err = tegra_xusb_pad_register(pad, &tegra210_pcie_phy_ops); 281887d66f28SThierry Reding if (err < 0) 281987d66f28SThierry Reding goto unregister; 282087d66f28SThierry Reding 282187d66f28SThierry Reding dev_set_drvdata(&pad->dev, pad); 282287d66f28SThierry Reding 282387d66f28SThierry Reding return pad; 282487d66f28SThierry Reding 282587d66f28SThierry Reding unregister: 282687d66f28SThierry Reding device_unregister(&pad->dev); 282787d66f28SThierry Reding out: 282887d66f28SThierry Reding return ERR_PTR(err); 282987d66f28SThierry Reding } 283087d66f28SThierry Reding 283187d66f28SThierry Reding static void tegra210_pcie_pad_remove(struct tegra_xusb_pad *pad) 283287d66f28SThierry Reding { 283387d66f28SThierry Reding struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(pad); 283487d66f28SThierry Reding 283587d66f28SThierry Reding kfree(pcie); 283687d66f28SThierry Reding } 283787d66f28SThierry Reding 283887d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_pcie_ops = { 283987d66f28SThierry Reding .probe = tegra210_pcie_pad_probe, 284087d66f28SThierry Reding .remove = tegra210_pcie_pad_remove, 284187d66f28SThierry Reding }; 284287d66f28SThierry Reding 284387d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_pcie_pad = { 284487d66f28SThierry Reding .name = "pcie", 284587d66f28SThierry Reding .num_lanes = ARRAY_SIZE(tegra210_pcie_lanes), 284687d66f28SThierry Reding .lanes = tegra210_pcie_lanes, 284787d66f28SThierry Reding .ops = &tegra210_pcie_ops, 284887d66f28SThierry Reding }; 284987d66f28SThierry Reding 285087d66f28SThierry Reding static const struct tegra_xusb_lane_soc tegra210_sata_lanes[] = { 2851c339605cSJC Kuo TEGRA210_UPHY_LANE("sata-0", 0x028, 30, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2), 285287d66f28SThierry Reding }; 285387d66f28SThierry Reding 285487d66f28SThierry Reding static struct tegra_xusb_lane * 285587d66f28SThierry Reding tegra210_sata_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, 285687d66f28SThierry Reding unsigned int index) 285787d66f28SThierry Reding { 285887d66f28SThierry Reding struct tegra_xusb_sata_lane *sata; 285987d66f28SThierry Reding int err; 286087d66f28SThierry Reding 286187d66f28SThierry Reding sata = kzalloc(sizeof(*sata), GFP_KERNEL); 286287d66f28SThierry Reding if (!sata) 286387d66f28SThierry Reding return ERR_PTR(-ENOMEM); 286487d66f28SThierry Reding 286587d66f28SThierry Reding INIT_LIST_HEAD(&sata->base.list); 286687d66f28SThierry Reding sata->base.soc = &pad->soc->lanes[index]; 286787d66f28SThierry Reding sata->base.index = index; 286887d66f28SThierry Reding sata->base.pad = pad; 286987d66f28SThierry Reding sata->base.np = np; 287087d66f28SThierry Reding 287187d66f28SThierry Reding err = tegra_xusb_lane_parse_dt(&sata->base, np); 287287d66f28SThierry Reding if (err < 0) { 287387d66f28SThierry Reding kfree(sata); 287487d66f28SThierry Reding return ERR_PTR(err); 287587d66f28SThierry Reding } 287687d66f28SThierry Reding 287787d66f28SThierry Reding return &sata->base; 287887d66f28SThierry Reding } 287987d66f28SThierry Reding 288087d66f28SThierry Reding static void tegra210_sata_lane_remove(struct tegra_xusb_lane *lane) 288187d66f28SThierry Reding { 288287d66f28SThierry Reding struct tegra_xusb_sata_lane *sata = to_sata_lane(lane); 288387d66f28SThierry Reding 288487d66f28SThierry Reding kfree(sata); 288587d66f28SThierry Reding } 288687d66f28SThierry Reding 288787d66f28SThierry Reding static const struct tegra_xusb_lane_ops tegra210_sata_lane_ops = { 288887d66f28SThierry Reding .probe = tegra210_sata_lane_probe, 288987d66f28SThierry Reding .remove = tegra210_sata_lane_remove, 2890c339605cSJC Kuo .iddq_enable = tegra210_uphy_lane_iddq_enable, 2891c339605cSJC Kuo .iddq_disable = tegra210_uphy_lane_iddq_disable, 28922d102148SJC Kuo .enable_phy_sleepwalk = tegra210_usb3_enable_phy_sleepwalk, 28932d102148SJC Kuo .disable_phy_sleepwalk = tegra210_usb3_disable_phy_sleepwalk, 28942d102148SJC Kuo .enable_phy_wake = tegra210_usb3_enable_phy_wake, 28952d102148SJC Kuo .disable_phy_wake = tegra210_usb3_disable_phy_wake, 28962d102148SJC Kuo .remote_wake_detected = tegra210_usb3_phy_remote_wake_detected, 289787d66f28SThierry Reding }; 289887d66f28SThierry Reding 289987d66f28SThierry Reding static int tegra210_sata_phy_init(struct phy *phy) 290087d66f28SThierry Reding { 290187d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 29022352fdb0SJC Kuo struct tegra_xusb_padctl *padctl = lane->pad->padctl; 290387d66f28SThierry Reding 29042352fdb0SJC Kuo mutex_lock(&padctl->lock); 290587d66f28SThierry Reding 29062352fdb0SJC Kuo tegra210_uphy_init(padctl); 290787d66f28SThierry Reding 29082352fdb0SJC Kuo mutex_unlock(&padctl->lock); 29092352fdb0SJC Kuo return 0; 291087d66f28SThierry Reding } 291187d66f28SThierry Reding 291287d66f28SThierry Reding static int tegra210_sata_phy_power_on(struct phy *phy) 291387d66f28SThierry Reding { 291487d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 291587d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 29162352fdb0SJC Kuo int err = 0; 291787d66f28SThierry Reding 291887d66f28SThierry Reding mutex_lock(&padctl->lock); 291987d66f28SThierry Reding 292023d5ec3fSJC Kuo if (tegra_xusb_lane_check(lane, "usb3-ss")) 292123d5ec3fSJC Kuo err = tegra210_usb3_phy_power_on(phy); 292223d5ec3fSJC Kuo 292387d66f28SThierry Reding mutex_unlock(&padctl->lock); 292487d66f28SThierry Reding return err; 292587d66f28SThierry Reding } 292687d66f28SThierry Reding 292787d66f28SThierry Reding static int tegra210_sata_phy_power_off(struct phy *phy) 292887d66f28SThierry Reding { 292987d66f28SThierry Reding struct tegra_xusb_lane *lane = phy_get_drvdata(phy); 293087d66f28SThierry Reding struct tegra_xusb_padctl *padctl = lane->pad->padctl; 293123d5ec3fSJC Kuo int err = 0; 293287d66f28SThierry Reding 293323d5ec3fSJC Kuo mutex_lock(&padctl->lock); 293423d5ec3fSJC Kuo 293523d5ec3fSJC Kuo if (tegra_xusb_lane_check(lane, "usb3-ss")) 293623d5ec3fSJC Kuo err = tegra210_usb3_phy_power_off(phy); 293723d5ec3fSJC Kuo 293823d5ec3fSJC Kuo mutex_unlock(&padctl->lock); 293923d5ec3fSJC Kuo return err; 294087d66f28SThierry Reding } 294187d66f28SThierry Reding 294287d66f28SThierry Reding static const struct phy_ops tegra210_sata_phy_ops = { 294387d66f28SThierry Reding .init = tegra210_sata_phy_init, 294487d66f28SThierry Reding .power_on = tegra210_sata_phy_power_on, 294587d66f28SThierry Reding .power_off = tegra210_sata_phy_power_off, 294687d66f28SThierry Reding .owner = THIS_MODULE, 294787d66f28SThierry Reding }; 294887d66f28SThierry Reding 294987d66f28SThierry Reding static struct tegra_xusb_pad * 295087d66f28SThierry Reding tegra210_sata_pad_probe(struct tegra_xusb_padctl *padctl, 295187d66f28SThierry Reding const struct tegra_xusb_pad_soc *soc, 295287d66f28SThierry Reding struct device_node *np) 295387d66f28SThierry Reding { 295487d66f28SThierry Reding struct tegra_xusb_sata_pad *sata; 295587d66f28SThierry Reding struct tegra_xusb_pad *pad; 295687d66f28SThierry Reding int err; 295787d66f28SThierry Reding 295887d66f28SThierry Reding sata = kzalloc(sizeof(*sata), GFP_KERNEL); 295987d66f28SThierry Reding if (!sata) 296087d66f28SThierry Reding return ERR_PTR(-ENOMEM); 296187d66f28SThierry Reding 296287d66f28SThierry Reding pad = &sata->base; 296387d66f28SThierry Reding pad->ops = &tegra210_sata_lane_ops; 296487d66f28SThierry Reding pad->soc = soc; 296587d66f28SThierry Reding 296687d66f28SThierry Reding err = tegra_xusb_pad_init(pad, padctl, np); 296787d66f28SThierry Reding if (err < 0) { 296887d66f28SThierry Reding kfree(sata); 296987d66f28SThierry Reding goto out; 297087d66f28SThierry Reding } 297187d66f28SThierry Reding 297287d66f28SThierry Reding sata->rst = devm_reset_control_get(&pad->dev, "phy"); 297387d66f28SThierry Reding if (IS_ERR(sata->rst)) { 297487d66f28SThierry Reding err = PTR_ERR(sata->rst); 297587d66f28SThierry Reding dev_err(&pad->dev, "failed to get SATA pad reset: %d\n", err); 297687d66f28SThierry Reding goto unregister; 297787d66f28SThierry Reding } 297887d66f28SThierry Reding 297987d66f28SThierry Reding err = tegra_xusb_pad_register(pad, &tegra210_sata_phy_ops); 298087d66f28SThierry Reding if (err < 0) 298187d66f28SThierry Reding goto unregister; 298287d66f28SThierry Reding 298387d66f28SThierry Reding dev_set_drvdata(&pad->dev, pad); 298487d66f28SThierry Reding 298587d66f28SThierry Reding return pad; 298687d66f28SThierry Reding 298787d66f28SThierry Reding unregister: 298887d66f28SThierry Reding device_unregister(&pad->dev); 298987d66f28SThierry Reding out: 299087d66f28SThierry Reding return ERR_PTR(err); 299187d66f28SThierry Reding } 299287d66f28SThierry Reding 299387d66f28SThierry Reding static void tegra210_sata_pad_remove(struct tegra_xusb_pad *pad) 299487d66f28SThierry Reding { 299587d66f28SThierry Reding struct tegra_xusb_sata_pad *sata = to_sata_pad(pad); 299687d66f28SThierry Reding 299787d66f28SThierry Reding kfree(sata); 299887d66f28SThierry Reding } 299987d66f28SThierry Reding 300087d66f28SThierry Reding static const struct tegra_xusb_pad_ops tegra210_sata_ops = { 300187d66f28SThierry Reding .probe = tegra210_sata_pad_probe, 300287d66f28SThierry Reding .remove = tegra210_sata_pad_remove, 300387d66f28SThierry Reding }; 300487d66f28SThierry Reding 300587d66f28SThierry Reding static const struct tegra_xusb_pad_soc tegra210_sata_pad = { 300687d66f28SThierry Reding .name = "sata", 300787d66f28SThierry Reding .num_lanes = ARRAY_SIZE(tegra210_sata_lanes), 300887d66f28SThierry Reding .lanes = tegra210_sata_lanes, 300987d66f28SThierry Reding .ops = &tegra210_sata_ops, 301087d66f28SThierry Reding }; 301187d66f28SThierry Reding 301287d66f28SThierry Reding static const struct tegra_xusb_pad_soc * const tegra210_pads[] = { 301387d66f28SThierry Reding &tegra210_usb2_pad, 301487d66f28SThierry Reding &tegra210_hsic_pad, 301587d66f28SThierry Reding &tegra210_pcie_pad, 301687d66f28SThierry Reding &tegra210_sata_pad, 301787d66f28SThierry Reding }; 301887d66f28SThierry Reding 301987d66f28SThierry Reding static int tegra210_usb2_port_enable(struct tegra_xusb_port *port) 302087d66f28SThierry Reding { 302187d66f28SThierry Reding return 0; 302287d66f28SThierry Reding } 302387d66f28SThierry Reding 302487d66f28SThierry Reding static void tegra210_usb2_port_disable(struct tegra_xusb_port *port) 302587d66f28SThierry Reding { 302687d66f28SThierry Reding } 302787d66f28SThierry Reding 302887d66f28SThierry Reding static struct tegra_xusb_lane * 302987d66f28SThierry Reding tegra210_usb2_port_map(struct tegra_xusb_port *port) 303087d66f28SThierry Reding { 303187d66f28SThierry Reding return tegra_xusb_find_lane(port->padctl, "usb2", port->index); 303287d66f28SThierry Reding } 303387d66f28SThierry Reding 303487d66f28SThierry Reding static const struct tegra_xusb_port_ops tegra210_usb2_port_ops = { 3035e78fdbadSThierry Reding .release = tegra_xusb_usb2_port_release, 30362f8da84dSThierry Reding .remove = tegra_xusb_usb2_port_remove, 303787d66f28SThierry Reding .enable = tegra210_usb2_port_enable, 303887d66f28SThierry Reding .disable = tegra210_usb2_port_disable, 303987d66f28SThierry Reding .map = tegra210_usb2_port_map, 304087d66f28SThierry Reding }; 304187d66f28SThierry Reding 304287d66f28SThierry Reding static int tegra210_hsic_port_enable(struct tegra_xusb_port *port) 304387d66f28SThierry Reding { 304487d66f28SThierry Reding return 0; 304587d66f28SThierry Reding } 304687d66f28SThierry Reding 304787d66f28SThierry Reding static void tegra210_hsic_port_disable(struct tegra_xusb_port *port) 304887d66f28SThierry Reding { 304987d66f28SThierry Reding } 305087d66f28SThierry Reding 305187d66f28SThierry Reding static struct tegra_xusb_lane * 305287d66f28SThierry Reding tegra210_hsic_port_map(struct tegra_xusb_port *port) 305387d66f28SThierry Reding { 305487d66f28SThierry Reding return tegra_xusb_find_lane(port->padctl, "hsic", port->index); 305587d66f28SThierry Reding } 305687d66f28SThierry Reding 305787d66f28SThierry Reding static const struct tegra_xusb_port_ops tegra210_hsic_port_ops = { 3058e78fdbadSThierry Reding .release = tegra_xusb_hsic_port_release, 305987d66f28SThierry Reding .enable = tegra210_hsic_port_enable, 306087d66f28SThierry Reding .disable = tegra210_hsic_port_disable, 306187d66f28SThierry Reding .map = tegra210_hsic_port_map, 306287d66f28SThierry Reding }; 306387d66f28SThierry Reding 306487d66f28SThierry Reding static int tegra210_usb3_port_enable(struct tegra_xusb_port *port) 306587d66f28SThierry Reding { 306687d66f28SThierry Reding return 0; 306787d66f28SThierry Reding } 306887d66f28SThierry Reding 306987d66f28SThierry Reding static void tegra210_usb3_port_disable(struct tegra_xusb_port *port) 307087d66f28SThierry Reding { 307187d66f28SThierry Reding } 307287d66f28SThierry Reding 307387d66f28SThierry Reding static struct tegra_xusb_lane * 307487d66f28SThierry Reding tegra210_usb3_port_map(struct tegra_xusb_port *port) 307587d66f28SThierry Reding { 307687d66f28SThierry Reding return tegra_xusb_port_find_lane(port, tegra210_usb3_map, "usb3-ss"); 307787d66f28SThierry Reding } 307887d66f28SThierry Reding 307987d66f28SThierry Reding static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = { 3080e78fdbadSThierry Reding .release = tegra_xusb_usb3_port_release, 30812f8da84dSThierry Reding .remove = tegra_xusb_usb3_port_remove, 308287d66f28SThierry Reding .enable = tegra210_usb3_port_enable, 308387d66f28SThierry Reding .disable = tegra210_usb3_port_disable, 308487d66f28SThierry Reding .map = tegra210_usb3_port_map, 308587d66f28SThierry Reding }; 308687d66f28SThierry Reding 308790767cdfSNagarjuna Kristam static int tegra210_utmi_port_reset(struct phy *phy) 308890767cdfSNagarjuna Kristam { 308990767cdfSNagarjuna Kristam struct tegra_xusb_padctl *padctl; 309090767cdfSNagarjuna Kristam struct tegra_xusb_lane *lane; 309190767cdfSNagarjuna Kristam u32 value; 309290767cdfSNagarjuna Kristam 309390767cdfSNagarjuna Kristam lane = phy_get_drvdata(phy); 309490767cdfSNagarjuna Kristam padctl = lane->pad->padctl; 309590767cdfSNagarjuna Kristam 309690767cdfSNagarjuna Kristam value = padctl_readl(padctl, 309790767cdfSNagarjuna Kristam XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL0(lane->index)); 309890767cdfSNagarjuna Kristam 309990767cdfSNagarjuna Kristam if ((value & XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIP) || 310090767cdfSNagarjuna Kristam (value & XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL0_ZIN)) { 310190767cdfSNagarjuna Kristam tegra210_xusb_padctl_vbus_override(padctl, false); 310290767cdfSNagarjuna Kristam tegra210_xusb_padctl_vbus_override(padctl, true); 310390767cdfSNagarjuna Kristam return 1; 310490767cdfSNagarjuna Kristam } 310590767cdfSNagarjuna Kristam 310690767cdfSNagarjuna Kristam return 0; 310790767cdfSNagarjuna Kristam } 310890767cdfSNagarjuna Kristam 310987d66f28SThierry Reding static int 311087d66f28SThierry Reding tegra210_xusb_read_fuse_calibration(struct tegra210_xusb_fuse_calibration *fuse) 311187d66f28SThierry Reding { 311287d66f28SThierry Reding unsigned int i; 311387d66f28SThierry Reding u32 value; 311487d66f28SThierry Reding int err; 311587d66f28SThierry Reding 311687d66f28SThierry Reding err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value); 311787d66f28SThierry Reding if (err < 0) 311887d66f28SThierry Reding return err; 311987d66f28SThierry Reding 312087d66f28SThierry Reding for (i = 0; i < ARRAY_SIZE(fuse->hs_curr_level); i++) { 312187d66f28SThierry Reding fuse->hs_curr_level[i] = 312287d66f28SThierry Reding (value >> FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(i)) & 312387d66f28SThierry Reding FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK; 312487d66f28SThierry Reding } 312587d66f28SThierry Reding 312687d66f28SThierry Reding fuse->hs_term_range_adj = 312787d66f28SThierry Reding (value >> FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT) & 312887d66f28SThierry Reding FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK; 312987d66f28SThierry Reding 313087d66f28SThierry Reding err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value); 313187d66f28SThierry Reding if (err < 0) 313287d66f28SThierry Reding return err; 313387d66f28SThierry Reding 313487d66f28SThierry Reding fuse->rpd_ctrl = 313587d66f28SThierry Reding (value >> FUSE_USB_CALIB_EXT_RPD_CTRL_SHIFT) & 313687d66f28SThierry Reding FUSE_USB_CALIB_EXT_RPD_CTRL_MASK; 313787d66f28SThierry Reding 313887d66f28SThierry Reding return 0; 313987d66f28SThierry Reding } 314087d66f28SThierry Reding 314187d66f28SThierry Reding static struct tegra_xusb_padctl * 314287d66f28SThierry Reding tegra210_xusb_padctl_probe(struct device *dev, 314387d66f28SThierry Reding const struct tegra_xusb_padctl_soc *soc) 314487d66f28SThierry Reding { 314587d66f28SThierry Reding struct tegra210_xusb_padctl *padctl; 31462d102148SJC Kuo struct platform_device *pdev; 31472d102148SJC Kuo struct device_node *np; 314887d66f28SThierry Reding int err; 314987d66f28SThierry Reding 315087d66f28SThierry Reding padctl = devm_kzalloc(dev, sizeof(*padctl), GFP_KERNEL); 315187d66f28SThierry Reding if (!padctl) 315287d66f28SThierry Reding return ERR_PTR(-ENOMEM); 315387d66f28SThierry Reding 315487d66f28SThierry Reding padctl->base.dev = dev; 315587d66f28SThierry Reding padctl->base.soc = soc; 315687d66f28SThierry Reding 315787d66f28SThierry Reding err = tegra210_xusb_read_fuse_calibration(&padctl->fuse); 315887d66f28SThierry Reding if (err < 0) 315987d66f28SThierry Reding return ERR_PTR(err); 316087d66f28SThierry Reding 31612d102148SJC Kuo np = of_parse_phandle(dev->of_node, "nvidia,pmc", 0); 31622d102148SJC Kuo if (!np) { 31632d102148SJC Kuo dev_warn(dev, "nvidia,pmc property is missing\n"); 31642d102148SJC Kuo goto out; 31652d102148SJC Kuo } 31662d102148SJC Kuo 31672d102148SJC Kuo pdev = of_find_device_by_node(np); 31682d102148SJC Kuo if (!pdev) { 31692d102148SJC Kuo dev_warn(dev, "PMC device is not available\n"); 31702d102148SJC Kuo goto out; 31712d102148SJC Kuo } 31722d102148SJC Kuo 31732d102148SJC Kuo if (!platform_get_drvdata(pdev)) 31742d102148SJC Kuo return ERR_PTR(-EPROBE_DEFER); 31752d102148SJC Kuo 31762d102148SJC Kuo padctl->regmap = dev_get_regmap(&pdev->dev, "usb_sleepwalk"); 31772d102148SJC Kuo if (!padctl->regmap) 31782d102148SJC Kuo dev_info(dev, "failed to find PMC regmap\n"); 31792d102148SJC Kuo 31802d102148SJC Kuo out: 318187d66f28SThierry Reding return &padctl->base; 318287d66f28SThierry Reding } 318387d66f28SThierry Reding 318487d66f28SThierry Reding static void tegra210_xusb_padctl_remove(struct tegra_xusb_padctl *padctl) 318587d66f28SThierry Reding { 318687d66f28SThierry Reding } 318787d66f28SThierry Reding 31882d102148SJC Kuo static void tegra210_xusb_padctl_save(struct tegra_xusb_padctl *padctl) 31892d102148SJC Kuo { 31902d102148SJC Kuo struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl); 31912d102148SJC Kuo 31922d102148SJC Kuo priv->context.usb2_pad_mux = 31932d102148SJC Kuo padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX); 31942d102148SJC Kuo priv->context.usb2_port_cap = 31952d102148SJC Kuo padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP); 31962d102148SJC Kuo priv->context.ss_port_map = 31972d102148SJC Kuo padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); 31982d102148SJC Kuo priv->context.usb3_pad_mux = 31992d102148SJC Kuo padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX); 32002d102148SJC Kuo } 32012d102148SJC Kuo 32022d102148SJC Kuo static void tegra210_xusb_padctl_restore(struct tegra_xusb_padctl *padctl) 32032d102148SJC Kuo { 32042d102148SJC Kuo struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl); 32052d102148SJC Kuo struct tegra_xusb_lane *lane; 32062d102148SJC Kuo 32072d102148SJC Kuo padctl_writel(padctl, priv->context.usb2_pad_mux, 32082d102148SJC Kuo XUSB_PADCTL_USB2_PAD_MUX); 32092d102148SJC Kuo padctl_writel(padctl, priv->context.usb2_port_cap, 32102d102148SJC Kuo XUSB_PADCTL_USB2_PORT_CAP); 32112d102148SJC Kuo padctl_writel(padctl, priv->context.ss_port_map, 32122d102148SJC Kuo XUSB_PADCTL_SS_PORT_MAP); 32132d102148SJC Kuo 32142d102148SJC Kuo list_for_each_entry(lane, &padctl->lanes, list) { 32152d102148SJC Kuo if (lane->pad->ops->iddq_enable) 32162d102148SJC Kuo tegra210_uphy_lane_iddq_enable(lane); 32172d102148SJC Kuo } 32182d102148SJC Kuo 32192d102148SJC Kuo padctl_writel(padctl, priv->context.usb3_pad_mux, 32202d102148SJC Kuo XUSB_PADCTL_USB3_PAD_MUX); 32212d102148SJC Kuo 32222d102148SJC Kuo list_for_each_entry(lane, &padctl->lanes, list) { 32232d102148SJC Kuo if (lane->pad->ops->iddq_disable) 32242d102148SJC Kuo tegra210_uphy_lane_iddq_disable(lane); 32252d102148SJC Kuo } 32262d102148SJC Kuo } 32272d102148SJC Kuo 32282d102148SJC Kuo static int tegra210_xusb_padctl_suspend_noirq(struct tegra_xusb_padctl *padctl) 32292d102148SJC Kuo { 32302d102148SJC Kuo mutex_lock(&padctl->lock); 32312d102148SJC Kuo 32322d102148SJC Kuo tegra210_uphy_deinit(padctl); 32332d102148SJC Kuo 32342d102148SJC Kuo tegra210_xusb_padctl_save(padctl); 32352d102148SJC Kuo 32362d102148SJC Kuo mutex_unlock(&padctl->lock); 32372d102148SJC Kuo return 0; 32382d102148SJC Kuo } 32392d102148SJC Kuo 32402d102148SJC Kuo static int tegra210_xusb_padctl_resume_noirq(struct tegra_xusb_padctl *padctl) 32412d102148SJC Kuo { 32422d102148SJC Kuo mutex_lock(&padctl->lock); 32432d102148SJC Kuo 32442d102148SJC Kuo tegra210_xusb_padctl_restore(padctl); 32452d102148SJC Kuo 32462d102148SJC Kuo tegra210_uphy_init(padctl); 32472d102148SJC Kuo 32482d102148SJC Kuo mutex_unlock(&padctl->lock); 32492d102148SJC Kuo return 0; 32502d102148SJC Kuo } 32512d102148SJC Kuo 325287d66f28SThierry Reding static const struct tegra_xusb_padctl_ops tegra210_xusb_padctl_ops = { 325387d66f28SThierry Reding .probe = tegra210_xusb_padctl_probe, 325487d66f28SThierry Reding .remove = tegra210_xusb_padctl_remove, 32552d102148SJC Kuo .suspend_noirq = tegra210_xusb_padctl_suspend_noirq, 32562d102148SJC Kuo .resume_noirq = tegra210_xusb_padctl_resume_noirq, 325787d66f28SThierry Reding .usb3_set_lfps_detect = tegra210_usb3_set_lfps_detect, 325887d66f28SThierry Reding .hsic_set_idle = tegra210_hsic_set_idle, 325990767cdfSNagarjuna Kristam .vbus_override = tegra210_xusb_padctl_vbus_override, 326090767cdfSNagarjuna Kristam .utmi_port_reset = tegra210_utmi_port_reset, 326187d66f28SThierry Reding }; 326287d66f28SThierry Reding 3263e3888cdaSThierry Reding static const char * const tegra210_xusb_padctl_supply_names[] = { 3264e3888cdaSThierry Reding "avdd-pll-utmip", 3265e3888cdaSThierry Reding "avdd-pll-uerefe", 3266e3888cdaSThierry Reding "dvdd-pex-pll", 3267e3888cdaSThierry Reding "hvdd-pex-pll-e", 3268e3888cdaSThierry Reding }; 3269e3888cdaSThierry Reding 327087d66f28SThierry Reding const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc = { 327187d66f28SThierry Reding .num_pads = ARRAY_SIZE(tegra210_pads), 327287d66f28SThierry Reding .pads = tegra210_pads, 327387d66f28SThierry Reding .ports = { 327487d66f28SThierry Reding .usb2 = { 327587d66f28SThierry Reding .ops = &tegra210_usb2_port_ops, 327687d66f28SThierry Reding .count = 4, 327787d66f28SThierry Reding }, 327887d66f28SThierry Reding .hsic = { 327987d66f28SThierry Reding .ops = &tegra210_hsic_port_ops, 328087d66f28SThierry Reding .count = 1, 328187d66f28SThierry Reding }, 328287d66f28SThierry Reding .usb3 = { 328387d66f28SThierry Reding .ops = &tegra210_usb3_port_ops, 328487d66f28SThierry Reding .count = 4, 328587d66f28SThierry Reding }, 328687d66f28SThierry Reding }, 328787d66f28SThierry Reding .ops = &tegra210_xusb_padctl_ops, 3288e3888cdaSThierry Reding .supply_names = tegra210_xusb_padctl_supply_names, 3289e3888cdaSThierry Reding .num_supplies = ARRAY_SIZE(tegra210_xusb_padctl_supply_names), 3290a5be28c3SNagarjuna Kristam .need_fake_usb3_port = true, 329187d66f28SThierry Reding }; 329287d66f28SThierry Reding EXPORT_SYMBOL_GPL(tegra210_xusb_padctl_soc); 329387d66f28SThierry Reding 329487d66f28SThierry Reding MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>"); 329587d66f28SThierry Reding MODULE_DESCRIPTION("NVIDIA Tegra 210 XUSB Pad Controller driver"); 329687d66f28SThierry Reding MODULE_LICENSE("GPL v2"); 3297