Hi, On Tuesday 25 November 2014 05:47 AM, Andrew Bresticker wrote: > In addition to the PCIe and SATA PHYs, the XUSB pad controller also > supports 3 UTMI, 2 HSIC, and 2 USB3 PHYs. Each USB3 PHY uses a single > PCIe or SATA lane and is mapped to one of the three UTMI ports. > > The xHCI controller will also send messages intended for the PHY driver, > so request and listen for messages on the mailbox's PHY channel. > > Signed-off-by: Andrew Bresticker <abrestic@xxxxxxxxxxxx> > Acked-by: Linus Walleij <linus.walleij@xxxxxxxxxx> > Reviewed-by: Stephen Warren <swarren@xxxxxxxxxx> > --- > No changes from v5. > Changes from v4: > - Disabled USB support on missing mailbox channel instead of failing > to probe. > - Made usb3-port a pinconfig property. > - Addressed review comments from Thierry. > No changes from v3. > Changes from v2: > - Added support for nvidia,otg-hs-curr-level-offset property. > - Moved mailbox request handling to workqueue. > - Added filtering out of non-PHY mailbox messages. > - Dropped "-otg" from VBUS supplies. > Changes from v1: > - Updated to use common mailbox API. > - Added SATA PHY enable sequence for USB3 ports using the SATA lane. > - Made USB3 port-to-lane mappins a top-level binding rather than a pinconfig > binding. > --- > drivers/pinctrl/Kconfig | 1 + > drivers/pinctrl/pinctrl-tegra-xusb.c | 1262 +++++++++++++++++++++++++++++++++- > include/soc/tegra/xusb.h | 7 + > 3 files changed, 1254 insertions(+), 16 deletions(-) The devm_phy_create() API has changed (see linux-phy next) and the patch that modified the existing devm_phy_create() in pinctrl-tegra-xusb.c has also been merged in linux-phy tree. Thanks Kishon > > diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig > index c6a66de..b2a96f3 100644 > --- a/drivers/pinctrl/Kconfig > +++ b/drivers/pinctrl/Kconfig > @@ -160,6 +160,7 @@ config PINCTRL_TEGRA124 > > config PINCTRL_TEGRA_XUSB > def_bool y if ARCH_TEGRA > + depends on MAILBOX > select GENERIC_PHY > select PINCONF > select PINMUX > diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c > index 1631ec9..37ad84e 100644 > --- a/drivers/pinctrl/pinctrl-tegra-xusb.c > +++ b/drivers/pinctrl/pinctrl-tegra-xusb.c > @@ -13,23 +13,54 @@ > > #include <linux/delay.h> > #include <linux/io.h> > +#include <linux/mailbox_client.h> > #include <linux/module.h> > #include <linux/of.h> > #include <linux/phy/phy.h> > #include <linux/pinctrl/pinctrl.h> > #include <linux/pinctrl/pinmux.h> > #include <linux/platform_device.h> > +#include <linux/regulator/consumer.h> > #include <linux/reset.h> > +#include <linux/workqueue.h> > + > +#include <soc/tegra/fuse.h> > +#include <soc/tegra/xusb.h> > > #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> > > #include "core.h" > #include "pinctrl-utils.h" > > +#define FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? 15 : 0) > +#define FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK 0x3f > +#define FUSE_SKU_CALIB_HS_IREF_CAP_SHIFT 13 > +#define FUSE_SKU_CALIB_HS_IREF_CAP_MASK 0x3 > +#define FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_SHIFT 11 > +#define FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_MASK 0x3 > +#define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT 7 > +#define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK 0xf > + > +#define XUSB_PADCTL_USB2_PORT_CAP 0x008 > +#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(x) ((x) * 4) > +#define XUSB_PADCTL_USB2_PORT_CAP_PORT_CAP_MASK 0x3 > +#define XUSB_PADCTL_USB2_PORT_CAP_DISABLED 0x0 > +#define XUSB_PADCTL_USB2_PORT_CAP_HOST 0x1 > +#define XUSB_PADCTL_USB2_PORT_CAP_DEVICE 0x2 > +#define XUSB_PADCTL_USB2_PORT_CAP_OTG 0x3 > + > +#define XUSB_PADCTL_SS_PORT_MAP 0x014 > +#define XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(x) ((x) * 4) > +#define XUSB_PADCTL_SS_PORT_MAP_PORT_MASK 0x7 > + > #define XUSB_PADCTL_ELPG_PROGRAM 0x01c > #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26) > #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25) > #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24) > +#define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(x) (1 << (18 + (x) * 4)) > +#define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(x) \ > + (1 << (17 + (x) * 4)) > +#define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN(x) (1 << (16 + (x) * 4)) > > #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040 > #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19) > @@ -41,17 +72,136 @@ > #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5) > #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4) > > +#define XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(x) (0x058 + (x) * 4) > +#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT 24 > +#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK 0xff > +#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT 16 > +#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK 0x3f > +#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT 8 > +#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK 0x3f > +#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT 8 > +#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK 0xffff > +#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT 4 > +#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK 0x7 > + > +#define XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(x) (0x068 + (x) * 4) > +#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT 24 > +#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK 0x1f > +#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT 16 > +#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK 0x7f > + > +#define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL2(x) ((x) < 2 ? 0x078 + (x) * 4 : \ > + 0x0f8 + (x) * 4) > +#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT 28 > +#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_MASK 0x3 > + > +#define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL5(x) ((x) < 2 ? 0x090 + (x) * 4 : \ > + 0x11c + (x) * 4) > +#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL5_RX_QEYE_EN (1 << 8) > + > +#define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL6(x) ((x) < 2 ? 0x098 + (x) * 4 : \ > + 0x128 + (x) * 4) > +#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT 24 > +#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK 0x3f > +#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_TAP_MASK 0x1f > +#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_AMP_MASK 0x7f > +#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT 16 > +#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK 0xff > +#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_G_Z 0x21 > +#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_TAP 0x32 > +#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_AMP 0x33 > +#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_CTLE_Z 0x48 > +#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_LATCH_G_Z 0xa1 > + > +#define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x0a0 + (x) * 4) > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI (1 << 21) > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 (1 << 20) > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD (1 << 19) > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT 14 > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_MASK 0x3 > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT 6 > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_MASK 0x3f > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT 0 > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK 0x3f > + > +#define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x) (0x0ac + (x) * 4) > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT 9 > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_MASK 0x3 > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT 3 > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK 0x7 > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2) > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP (1 << 1) > +#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP (1 << 0) > + > +#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x0b8 > +#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 12) > +#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT 2 > +#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK 0x7 > +#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT 0 > +#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK 0x3 > + > +#define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x0c0 + (x) * 4) > +#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT 12 > +#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK 0x7 > +#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT 8 > +#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK 0x7 > +#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT 4 > +#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK 0x7 > +#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT 0 > +#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK 0x7 > + > +#define XUSB_PADCTL_HSIC_PADX_CTL1(x) (0x0c8 + (x) * 4) > +#define XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE (1 << 10) > +#define XUSB_PADCTL_HSIC_PAD_CTL1_RPU_DATA (1 << 9) > +#define XUSB_PADCTL_HSIC_PAD_CTL1_RPD_STROBE (1 << 8) > +#define XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA (1 << 7) > +#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI (1 << 5) > +#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX (1 << 4) > +#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX (1 << 3) > +#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX (1 << 2) > +#define XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN (1 << 0) > + > +#define XUSB_PADCTL_HSIC_PADX_CTL2(x) (0x0d0 + (x) * 4) > +#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT 4 > +#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK 0x7 > +#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT 0 > +#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK 0x7 > + > +#define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL 0x0e0 > +#define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_STRB_TRIM_MASK 0x1f > + > #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138 > #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27) > #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24) > +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_SHIFT 20 > +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_MASK 0x3 > #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3) > #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST (1 << 1) > #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0) > > +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL2 0x13c > +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_SHIFT 20 > +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_MASK 0xf > +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_SHIFT 16 > +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_MASK 0xf > +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TCLKOUT_EN (1 << 12) > +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TXCLKREF_SEL (1 << 4) > +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_SHIFT 0 > +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_MASK 0x7 > + > +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL3 0x140 > +#define XUSB_PADCTL_IOPHY_PLL_S0_CTL3_RCAL_BYPASS (1 << 7) > + > #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148 > #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1) > #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0) > > +#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 0x14c > + > +#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 0x158 > + > +#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 0x15c > + > struct tegra_xusb_padctl_function { > const char *name; > const char * const *groups; > @@ -72,6 +222,16 @@ struct tegra_xusb_padctl_soc { > > const struct tegra_xusb_padctl_lane *lanes; > unsigned int num_lanes; > + > + u32 rx_wander; > + u32 rx_eq; > + u32 cdr_cntl; > + u32 dfe_cntl; > + u32 hs_slew; > + u32 ls_rslew[TEGRA_XUSB_UTMI_PHYS]; > + u32 hs_discon_level; > + u32 spare_in; > + unsigned int hsic_port_offset; > }; > > struct tegra_xusb_padctl_lane { > @@ -86,6 +246,22 @@ struct tegra_xusb_padctl_lane { > unsigned int num_funcs; > }; > > +struct tegra_xusb_fuse_calibration { > + u32 hs_curr_level[TEGRA_XUSB_UTMI_PHYS]; > + u32 hs_iref_cap; > + u32 hs_term_range_adj; > + u32 hs_squelch_level; > +}; > + > +struct tegra_xusb_usb3_port { > + unsigned int lane; > + bool context_saved; > + u32 tap1_val; > + u32 amp_val; > + u32 ctle_z_val; > + u32 ctle_g_val; > +}; > + > struct tegra_xusb_padctl { > struct device *dev; > void __iomem *regs; > @@ -93,13 +269,25 @@ struct tegra_xusb_padctl { > struct reset_control *rst; > > const struct tegra_xusb_padctl_soc *soc; > + struct tegra_xusb_fuse_calibration calib; > struct pinctrl_dev *pinctrl; > struct pinctrl_desc desc; > > struct phy_provider *provider; > - struct phy *phys[2]; > + struct phy *phys[TEGRA_XUSB_NUM_PHYS]; > > unsigned int enable; > + > + struct work_struct mbox_req_work; > + struct tegra_xusb_mbox_msg mbox_req; > + struct mbox_client mbox_client; > + struct mbox_chan *mbox_chan; > + > + struct tegra_xusb_usb3_port usb3_ports[TEGRA_XUSB_USB3_PHYS]; > + unsigned int utmi_enable; > + unsigned int hs_curr_level_offset[TEGRA_XUSB_UTMI_PHYS]; > + struct regulator *vbus[TEGRA_XUSB_UTMI_PHYS]; > + struct regulator *vddio_hsic; > }; > > static inline void padctl_writel(struct tegra_xusb_padctl *padctl, u32 value, > @@ -114,6 +302,53 @@ static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl, > return readl(padctl->regs + offset); > } > > +static inline struct tegra_xusb_padctl * > +mbox_work_to_padctl(struct work_struct *work) > +{ > + return container_of(work, struct tegra_xusb_padctl, mbox_req_work); > +} > + > +#define PIN_OTG_0 0 > +#define PIN_OTG_1 1 > +#define PIN_OTG_2 2 > +#define PIN_ULPI_0 3 > +#define PIN_HSIC_0 4 > +#define PIN_HSIC_1 5 > +#define PIN_PCIE_0 6 > +#define PIN_PCIE_1 7 > +#define PIN_PCIE_2 8 > +#define PIN_PCIE_3 9 > +#define PIN_PCIE_4 10 > +#define PIN_SATA_0 11 > + > +static inline bool lane_is_otg(unsigned int lane) > +{ > + return lane >= PIN_OTG_0 && lane <= PIN_OTG_2; > +} > + > +static inline bool lane_is_hsic(unsigned int lane) > +{ > + return lane >= PIN_HSIC_0 && lane <= PIN_HSIC_1; > +} > + > +static inline bool lane_is_pcie_or_sata(unsigned int lane) > +{ > + return lane >= PIN_PCIE_0 && lane <= PIN_SATA_0; > +} > + > +static int lane_to_usb3_port(struct tegra_xusb_padctl *padctl, > + unsigned int lane) > +{ > + unsigned int i; > + > + for (i = 0; i < TEGRA_XUSB_USB3_PHYS; i++) { > + if (padctl->usb3_ports[i].lane == lane) > + return i; > + } > + > + return -EINVAL; > +} > + > static int tegra_xusb_padctl_get_groups_count(struct pinctrl_dev *pinctrl) > { > struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl); > @@ -131,6 +366,17 @@ static const char *tegra_xusb_padctl_get_group_name(struct pinctrl_dev *pinctrl, > > enum tegra_xusb_padctl_param { > TEGRA_XUSB_PADCTL_IDDQ, > + TEGRA_XUSB_PADCTL_USB3_PORT, > + TEGRA_XUSB_PADCTL_USB2_PORT, > + TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM, > + TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM, > + TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM, > + TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN, > + TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP, > + TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN, > + TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP, > + TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM, > + TEGRA_XUSB_PADCTL_OTG_HS_CURR_LEVEL_OFFSET, > }; > > static const struct tegra_xusb_padctl_property { > @@ -138,6 +384,18 @@ static const struct tegra_xusb_padctl_property { > enum tegra_xusb_padctl_param param; > } properties[] = { > { "nvidia,iddq", TEGRA_XUSB_PADCTL_IDDQ }, > + { "nvidia,usb3-port", TEGRA_XUSB_PADCTL_USB3_PORT }, > + { "nvidia,usb2-port", TEGRA_XUSB_PADCTL_USB2_PORT }, > + { "nvidia,hsic-strobe-trim", TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM }, > + { "nvidia,hsic-rx-strobe-trim", TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM }, > + { "nvidia,hsic-rx-data-trim", TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM }, > + { "nvidia,hsic-tx-rtune-n", TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN }, > + { "nvidia,hsic-tx-rtune-p", TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP }, > + { "nvidia,hsic-tx-rslew-n", TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN }, > + { "nvidia,hsic-tx-rslew-p", TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP }, > + { "nvidia,hsic-auto-term", TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM }, > + { "nvidia,otg-hs-curr-level-offset", > + TEGRA_XUSB_PADCTL_OTG_HS_CURR_LEVEL_OFFSET }, > }; > > #define TEGRA_XUSB_PADCTL_PACK(param, value) ((param) << 16 | (value)) > @@ -322,6 +580,7 @@ static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl, > const struct tegra_xusb_padctl_lane *lane; > enum tegra_xusb_padctl_param param; > u32 value; > + int port; > > param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(*config); > lane = &padctl->soc->lanes[group]; > @@ -338,8 +597,136 @@ static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl, > value = 0; > else > value = 1; > + break; > > - *config = TEGRA_XUSB_PADCTL_PACK(param, value); > + case TEGRA_XUSB_PADCTL_USB3_PORT: > + value = lane_to_usb3_port(padctl, group); > + if (value < 0) { > + dev_err(padctl->dev, > + "Pin %d not mapped to USB3 port\n", group); > + return -EINVAL; > + } > + break; > + > + case TEGRA_XUSB_PADCTL_USB2_PORT: > + port = lane_to_usb3_port(padctl, group); > + if (port < 0) { > + dev_err(padctl->dev, > + "Pin %d not mapped to USB3 port\n", group); > + return -EINVAL; > + } > + > + value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP) >> > + XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(port); > + value &= XUSB_PADCTL_SS_PORT_MAP_PORT_MASK; > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", group); > + return -EINVAL; > + } > + > + value = padctl_readl(padctl, > + XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL); > + value &= XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_STRB_TRIM_MASK; > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", group); > + return -EINVAL; > + } > + > + port = group - PIN_HSIC_0; > + value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(port)) >> > + XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT; > + value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK; > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", group); > + return -EINVAL; > + } > + > + port = group - PIN_HSIC_0; > + value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(port)) >> > + XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT; > + value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK; > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", group); > + return -EINVAL; > + } > + > + port = group - PIN_HSIC_0; > + value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >> > + XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT; > + value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK; > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", group); > + return -EINVAL; > + } > + > + port = group - PIN_HSIC_0; > + value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >> > + XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT; > + value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK; > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", group); > + return -EINVAL; > + } > + > + port = group - PIN_HSIC_0; > + value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >> > + XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT; > + value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK; > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", group); > + return -EINVAL; > + } > + > + port = group - PIN_HSIC_0; > + value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >> > + XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT; > + value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK; > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", group); > + return -EINVAL; > + } > + > + port = group - PIN_HSIC_0; > + value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port)); > + if (value & XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN) > + value = 1; > + else > + value = 0; > + break; > + > + case TEGRA_XUSB_PADCTL_OTG_HS_CURR_LEVEL_OFFSET: > + if (!lane_is_otg(group)) { > + dev_err(padctl->dev, "Pin %d is not an OTG pad\n", > + group); > + return -EINVAL; > + } > + > + port = group - PIN_OTG_0; > + value = padctl->hs_curr_level_offset[port]; > break; > > default: > @@ -348,6 +735,7 @@ static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl, > return -ENOTSUPP; > } > > + *config = TEGRA_XUSB_PADCTL_PACK(param, value); > return 0; > } > > @@ -362,6 +750,7 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl, > unsigned long value; > unsigned int i; > u32 regval; > + int port; > > lane = &padctl->soc->lanes[group]; > > @@ -385,6 +774,206 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl, > padctl_writel(padctl, regval, lane->offset); > break; > > + case TEGRA_XUSB_PADCTL_USB3_PORT: > + if (value >= TEGRA_XUSB_USB3_PHYS) { > + dev_err(padctl->dev, "Invalid USB3 port: %lu\n", > + value); > + return -EINVAL; > + } > + if (!lane_is_pcie_or_sata(group)) { > + dev_err(padctl->dev, > + "USB3 port not applicable for pin %d\n", > + group); > + return -EINVAL; > + } > + > + padctl->usb3_ports[value].lane = group; > + break; > + > + case TEGRA_XUSB_PADCTL_USB2_PORT: > + if (value >= TEGRA_XUSB_UTMI_PHYS) { > + dev_err(padctl->dev, "Invalid USB2 port: %lu\n", > + value); > + return -EINVAL; > + } > + if (!lane_is_pcie_or_sata(group)) { > + dev_err(padctl->dev, > + "USB2 port not applicable for pin %d\n", > + group); > + return -EINVAL; > + } > + port = lane_to_usb3_port(padctl, group); > + if (port < 0) { > + dev_err(padctl->dev, > + "Pin %d not mapped to USB3 port\n", > + group); > + return -EINVAL; > + } > + > + regval = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP); > + regval &= ~(XUSB_PADCTL_SS_PORT_MAP_PORT_MASK << > + XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(port)); > + regval |= value << > + XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(port); > + padctl_writel(padctl, regval, XUSB_PADCTL_SS_PORT_MAP); > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", > + group); > + return -EINVAL; > + } > + > + value &= XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_STRB_TRIM_MASK; > + padctl_writel(padctl, value, > + XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL); > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", > + group); > + return -EINVAL; > + } > + > + port = group - PIN_HSIC_0; > + value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK; > + regval = padctl_readl(padctl, > + XUSB_PADCTL_HSIC_PADX_CTL2(port)); > + regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK << > + XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT); > + regval |= value << > + XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT; > + padctl_writel(padctl, regval, > + XUSB_PADCTL_HSIC_PADX_CTL2(port)); > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", > + group); > + return -EINVAL; > + } > + > + port = group - PIN_HSIC_0; > + value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK; > + regval = padctl_readl(padctl, > + XUSB_PADCTL_HSIC_PADX_CTL2(port)); > + regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK << > + XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT); > + regval |= value << > + XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT; > + padctl_writel(padctl, regval, > + XUSB_PADCTL_HSIC_PADX_CTL2(port)); > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", > + group); > + return -EINVAL; > + } > + > + port = group - PIN_HSIC_0; > + value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK; > + regval = padctl_readl(padctl, > + XUSB_PADCTL_HSIC_PADX_CTL0(port)); > + regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK << > + XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT); > + regval |= value << > + XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT; > + padctl_writel(padctl, regval, > + XUSB_PADCTL_HSIC_PADX_CTL0(port)); > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", > + group); > + return -EINVAL; > + } > + > + port = group - PIN_HSIC_0; > + value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK; > + regval = padctl_readl(padctl, > + XUSB_PADCTL_HSIC_PADX_CTL0(port)); > + regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK << > + XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT); > + regval |= value << > + XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT; > + padctl_writel(padctl, regval, > + XUSB_PADCTL_HSIC_PADX_CTL0(port)); > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", > + group); > + return -EINVAL; > + } > + > + port = group - PIN_HSIC_0; > + value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK; > + regval = padctl_readl(padctl, > + XUSB_PADCTL_HSIC_PADX_CTL0(port)); > + regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK << > + XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT); > + regval |= value << > + XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT; > + padctl_writel(padctl, regval, > + XUSB_PADCTL_HSIC_PADX_CTL0(port)); > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", > + group); > + return -EINVAL; > + } > + > + port = group - PIN_HSIC_0; > + value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK; > + regval = padctl_readl(padctl, > + XUSB_PADCTL_HSIC_PADX_CTL0(port)); > + regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK << > + XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT); > + regval |= value << > + XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT; > + padctl_writel(padctl, regval, > + XUSB_PADCTL_HSIC_PADX_CTL0(port)); > + break; > + > + case TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM: > + if (!lane_is_hsic(group)) { > + dev_err(padctl->dev, "Pin %d not an HSIC\n", > + group); > + return -EINVAL; > + } > + > + port = group - PIN_HSIC_0; > + regval = padctl_readl(padctl, > + XUSB_PADCTL_HSIC_PADX_CTL1(port)); > + if (!value) > + regval &= ~XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN; > + else > + regval |= XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN; > + padctl_writel(padctl, regval, > + XUSB_PADCTL_HSIC_PADX_CTL1(port)); > + break; > + > + case TEGRA_XUSB_PADCTL_OTG_HS_CURR_LEVEL_OFFSET: > + if (!lane_is_otg(group)) { > + dev_err(padctl->dev, > + "Pin %d is not an OTG pad\n", group); > + return -EINVAL; > + } > + > + port = group - PIN_OTG_0; > + value &= XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK; > + padctl->hs_curr_level_offset[port] = value; > + break; > + > default: > dev_err(padctl->dev, > "invalid configuration parameter: %04x\n", > @@ -671,6 +1260,548 @@ static const struct phy_ops sata_phy_ops = { > .owner = THIS_MODULE, > }; > > +static int usb3_phy_to_port(struct phy *phy) > +{ > + struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); > + unsigned int i; > + > + for (i = 0; i < TEGRA_XUSB_USB3_PHYS; i++) { > + if (phy == padctl->phys[TEGRA_XUSB_PADCTL_USB3_P0 + i]) > + return i; > + } > + WARN_ON(1); > + > + return -EINVAL; > +} > + > +static int usb3_phy_power_on(struct phy *phy) > +{ > + struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); > + int port = usb3_phy_to_port(phy); > + unsigned int lane; > + u32 value, offset; > + > + if (port < 0) > + return port; > + > + lane = padctl->usb3_ports[port].lane; > + if (!lane_is_pcie_or_sata(lane)) { > + dev_err(padctl->dev, "USB3 PHY %d mapped to invalid lane: %d\n", > + port, lane); > + return -EINVAL; > + } > + > + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port)); > + value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) | > + (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) | > + (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT)); > + value |= (padctl->soc->rx_wander << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) | > + (padctl->soc->cdr_cntl << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT) | > + (padctl->soc->rx_eq << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT); > + if (padctl->usb3_ports[port].context_saved) { > + value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) | > + (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT)); > + value |= (padctl->usb3_ports[port].ctle_g_val << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) | > + (padctl->usb3_ports[port].ctle_z_val << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT); > + } > + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port)); > + > + value = padctl->soc->dfe_cntl; > + if (padctl->usb3_ports[port].context_saved) { > + value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) | > + (XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT)); > + value |= (padctl->usb3_ports[port].tap1_val << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) | > + (padctl->usb3_ports[port].amp_val << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT); > + } > + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(port)); > + > + offset = (lane == PIN_SATA_0) ? > + XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 : > + XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL2(lane - PIN_PCIE_0); > + value = padctl_readl(padctl, offset); > + value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_MASK << > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT); > + value |= padctl->soc->spare_in << > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT; > + padctl_writel(padctl, value, offset); > + > + offset = (lane == PIN_SATA_0) ? > + XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 : > + XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL5(lane - PIN_PCIE_0); > + value = padctl_readl(padctl, offset); > + value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL5_RX_QEYE_EN; > + padctl_writel(padctl, value, offset); > + > + /* Enable SATA PHY when SATA lane is used */ > + if (lane == PIN_SATA_0) { > + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); > + value &= ~(XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_MASK << > + XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_SHIFT); > + value |= 0x2 << > + XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL0_REFCLK_NDIV_SHIFT; > + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); > + > + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL2); > + value &= ~((XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_MASK << > + XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_SHIFT) | > + (XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_MASK << > + XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_SHIFT) | > + (XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_MASK << > + XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_SHIFT) | > + XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TCLKOUT_EN); > + value |= (0x7 << > + XUSB_PADCTL_IOPHY_PLL_S0_CTL2_XDIGCLK_SEL_SHIFT) | > + (0x8 << > + XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL1_CP_CNTL_SHIFT) | > + (0x8 << > + XUSB_PADCTL_IOPHY_PLL_S0_CTL2_PLL0_CP_CNTL_SHIFT) | > + XUSB_PADCTL_IOPHY_PLL_S0_CTL2_TXCLKREF_SEL; > + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL2); > + > + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL3); > + value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL3_RCAL_BYPASS; > + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL3); > + } > + > + value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); > + value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port); > + padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); > + > + usleep_range(100, 200); > + > + value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); > + value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port); > + padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); > + > + value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); > + value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(port); > + padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); > + > + return 0; > +} > + > +static int usb3_phy_power_off(struct phy *phy) > +{ > + struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); > + int port = usb3_phy_to_port(phy); > + u32 value; > + > + if (port < 0) > + return port; > + > + value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); > + value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port); > + padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); > + > + usleep_range(100, 200); > + > + value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); > + value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port); > + padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); > + > + usleep_range(250, 350); > + > + value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM); > + value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(port); > + padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM); > + > + return 0; > +} > + > +static int usb3_phy_save_context(struct tegra_xusb_padctl *padctl, > + unsigned int port) > +{ > + unsigned int lane = padctl->usb3_ports[port].lane; > + u32 value, offset; > + > + if (port >= TEGRA_XUSB_USB3_PHYS) > + return -EINVAL; > + > + padctl->usb3_ports[port].context_saved = true; > + > + offset = (lane == PIN_SATA_0) ? > + XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 : > + XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL6(lane - PIN_PCIE_0); > + > + value = padctl_readl(padctl, offset); > + value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK << > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT); > + value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_TAP << > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT; > + padctl_writel(padctl, value, offset); > + > + value = padctl_readl(padctl, offset) >> > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT; > + padctl->usb3_ports[port].tap1_val = value & > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_TAP_MASK; > + > + value = padctl_readl(padctl, offset); > + value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK << > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT); > + value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_AMP << > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT; > + padctl_writel(padctl, value, offset); > + > + value = padctl_readl(padctl, offset) >> > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT; > + padctl->usb3_ports[port].amp_val = value & > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_AMP_MASK; > + > + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(port)); > + value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) | > + (XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT)); > + value |= (padctl->usb3_ports[port].tap1_val << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) | > + (padctl->usb3_ports[port].amp_val << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT); > + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(port)); > + > + value = padctl_readl(padctl, offset); > + value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK << > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT); > + value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_LATCH_G_Z << > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT; > + padctl_writel(padctl, value, offset); > + > + value = padctl_readl(padctl, offset); > + value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK << > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT); > + value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_G_Z << > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT; > + padctl_writel(padctl, value, offset); > + > + value = padctl_readl(padctl, offset) >> > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT; > + padctl->usb3_ports[port].ctle_g_val = value & > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK; > + > + value = padctl_readl(padctl, offset); > + value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK << > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT); > + value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_CTLE_Z << > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT; > + padctl_writel(padctl, value, offset); > + > + value = padctl_readl(padctl, offset) >> > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT; > + padctl->usb3_ports[port].ctle_z_val = value & > + XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK; > + > + value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port)); > + value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) | > + (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT)); > + value |= (padctl->usb3_ports[port].ctle_g_val << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) | > + (padctl->usb3_ports[port].ctle_z_val << > + XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT); > + padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port)); > + > + return 0; > +} > + > +static const struct phy_ops usb3_phy_ops = { > + .init = tegra_xusb_phy_init, > + .exit = tegra_xusb_phy_exit, > + .power_on = usb3_phy_power_on, > + .power_off = usb3_phy_power_off, > + .owner = THIS_MODULE, > +}; > + > +static int utmi_phy_to_port(struct phy *phy) > +{ > + struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); > + unsigned int i; > + > + for (i = 0; i < TEGRA_XUSB_UTMI_PHYS; i++) { > + if (phy == padctl->phys[TEGRA_XUSB_PADCTL_UTMI_P0 + i]) > + return i; > + } > + WARN_ON(1); > + > + return -EINVAL; > +} > + > +static int utmi_phy_power_on(struct phy *phy) > +{ > + struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); > + int port = utmi_phy_to_port(phy); > + int err; > + u32 value; > + > + if (port < 0) > + return port; > + > + value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); > + value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK << > + XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) | > + (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK << > + XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT)); > + value |= (padctl->calib.hs_squelch_level << > + XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) | > + (padctl->soc->hs_discon_level << > + XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT); > + padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); > + > + value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP); > + value &= ~(XUSB_PADCTL_USB2_PORT_CAP_PORT_CAP_MASK << > + XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(port)); > + value |= XUSB_PADCTL_USB2_PORT_CAP_HOST << > + XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(port); > + padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP); > + > + value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(port)); > + value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK << > + XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT) | > + (XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_MASK << > + XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT) | > + (XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_MASK << > + XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT) | > + XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD | > + XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 | > + XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI); > + value |= (padctl->calib.hs_curr_level[port] + > + padctl->hs_curr_level_offset[port]) << > + XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT; > + value |= padctl->soc->hs_slew << > + XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT; > + value |= padctl->soc->ls_rslew[port] << > + XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT; > + padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(port)); > + > + value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port)); > + value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK << > + XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) | > + (XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_MASK << > + XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT) | > + XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR | > + XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP | > + XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP); > + value |= (padctl->calib.hs_term_range_adj << > + XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) | > + (padctl->calib.hs_iref_cap << > + XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT); > + padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port)); > + > + err = regulator_enable(padctl->vbus[port]); > + if (err) > + return err; > + > + mutex_lock(&padctl->lock); > + > + if (padctl->utmi_enable++ > 0) > + goto out; > + > + value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); > + value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; > + padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); > + > +out: > + mutex_unlock(&padctl->lock); > + return 0; > +} > + > +static int utmi_phy_power_off(struct phy *phy) > +{ > + struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); > + int port = utmi_phy_to_port(phy); > + u32 value; > + > + if (port < 0) > + return port; > + > + regulator_disable(padctl->vbus[port]); > + > + mutex_lock(&padctl->lock); > + > + if (WARN_ON(padctl->utmi_enable == 0)) > + goto out; > + > + if (--padctl->utmi_enable > 0) > + goto out; > + > + value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); > + value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD; > + padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); > + > +out: > + mutex_unlock(&padctl->lock); > + return 0; > +} > + > +static const struct phy_ops utmi_phy_ops = { > + .init = tegra_xusb_phy_init, > + .exit = tegra_xusb_phy_exit, > + .power_on = utmi_phy_power_on, > + .power_off = utmi_phy_power_off, > + .owner = THIS_MODULE, > +}; > + > +static int hsic_phy_to_port(struct phy *phy) > +{ > + struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); > + unsigned int i; > + > + for (i = 0; i < TEGRA_XUSB_HSIC_PHYS; i++) { > + if (phy == padctl->phys[TEGRA_XUSB_PADCTL_HSIC_P0 + i]) > + return i; > + } > + WARN_ON(1); > + > + return -EINVAL; > +} > + > +static int hsic_phy_power_on(struct phy *phy) > +{ > + struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); > + int port = hsic_phy_to_port(phy); > + int err; > + u32 value; > + > + if (port < 0) > + return port; > + > + err = regulator_enable(padctl->vddio_hsic); > + if (err) > + return err; > + > + value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port)); > + value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_RPD_STROBE | > + XUSB_PADCTL_HSIC_PAD_CTL1_RPU_DATA | > + XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX | > + XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI | > + XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX | > + XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX); > + value |= XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA | > + XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE; > + padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(port)); > + > + return 0; > +} > + > +static int hsic_phy_power_off(struct phy *phy) > +{ > + struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy); > + int port = hsic_phy_to_port(phy); > + u32 value; > + > + if (port < 0) > + return port; > + > + value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port)); > + value |= XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX | > + XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI | > + XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX | > + XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX; > + padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(port)); > + > + regulator_disable(padctl->vddio_hsic); > + > + return 0; > +} > + > +static void hsic_phy_set_idle(struct tegra_xusb_padctl *padctl, > + unsigned int port, bool idle) > +{ > + u32 value; > + > + value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port)); > + if (idle) > + value |= XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA | > + XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE; > + else > + value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA | > + XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE); > + padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(port)); > +} > + > +static const struct phy_ops hsic_phy_ops = { > + .init = tegra_xusb_phy_init, > + .exit = tegra_xusb_phy_exit, > + .power_on = hsic_phy_power_on, > + .power_off = hsic_phy_power_off, > + .owner = THIS_MODULE, > +}; > + > +static void tegra_xusb_phy_mbox_work(struct work_struct *work) > +{ > + struct tegra_xusb_padctl *padctl = mbox_work_to_padctl(work); > + struct tegra_xusb_mbox_msg *msg = &padctl->mbox_req; > + struct tegra_xusb_mbox_msg resp; > + unsigned int i; > + u32 ports; > + > + resp.cmd = 0; > + switch (msg->cmd) { > + case MBOX_CMD_SAVE_DFE_CTLE_CTX: > + resp.data = msg->data; > + if (usb3_phy_save_context(padctl, msg->data) < 0) > + resp.cmd = MBOX_CMD_NAK; > + else > + resp.cmd = MBOX_CMD_ACK; > + break; > + case MBOX_CMD_START_HSIC_IDLE: > + case MBOX_CMD_STOP_HSIC_IDLE: > + ports = msg->data >> (padctl->soc->hsic_port_offset + 1); > + resp.data = msg->data; > + resp.cmd = MBOX_CMD_ACK; > + for (i = 0; i < TEGRA_XUSB_HSIC_PHYS; i++) { > + if (!(ports & BIT(i))) > + continue; > + if (msg->cmd == MBOX_CMD_START_HSIC_IDLE) > + hsic_phy_set_idle(padctl, i, true); > + else > + hsic_phy_set_idle(padctl, i, false); > + } > + break; > + default: > + break; > + } > + > + if (resp.cmd) > + mbox_send_message(padctl->mbox_chan, &resp); > +} > + > +static bool is_phy_mbox_message(u32 cmd) > +{ > + switch (cmd) { > + case MBOX_CMD_SAVE_DFE_CTLE_CTX: > + case MBOX_CMD_START_HSIC_IDLE: > + case MBOX_CMD_STOP_HSIC_IDLE: > + return true; > + default: > + return false; > + } > +} > + > +static void tegra_xusb_phy_mbox_rx(struct mbox_client *cl, void *data) > +{ > + struct tegra_xusb_padctl *padctl = dev_get_drvdata(cl->dev); > + struct tegra_xusb_mbox_msg *msg = data; > + > + if (is_phy_mbox_message(msg->cmd)) { > + padctl->mbox_req = *msg; > + schedule_work(&padctl->mbox_req_work); > + } > +} > + > static struct phy *tegra_xusb_padctl_xlate(struct device *dev, > struct of_phandle_args *args) > { > @@ -680,25 +1811,12 @@ static struct phy *tegra_xusb_padctl_xlate(struct device *dev, > if (args->args_count <= 0) > return ERR_PTR(-EINVAL); > > - if (index >= ARRAY_SIZE(padctl->phys)) > + if (index >= ARRAY_SIZE(padctl->phys) && !padctl->phys[index]) > return ERR_PTR(-EINVAL); > > return padctl->phys[index]; > } > > -#define PIN_OTG_0 0 > -#define PIN_OTG_1 1 > -#define PIN_OTG_2 2 > -#define PIN_ULPI_0 3 > -#define PIN_HSIC_0 4 > -#define PIN_HSIC_1 5 > -#define PIN_PCIE_0 6 > -#define PIN_PCIE_1 7 > -#define PIN_PCIE_2 8 > -#define PIN_PCIE_3 9 > -#define PIN_PCIE_4 10 > -#define PIN_SATA_0 11 > - > static const struct pinctrl_pin_desc tegra124_pins[] = { > PINCTRL_PIN(PIN_OTG_0, "otg-0"), > PINCTRL_PIN(PIN_OTG_1, "otg-1"), > @@ -856,6 +1974,15 @@ static const struct tegra_xusb_padctl_soc tegra124_soc = { > .functions = tegra124_functions, > .num_lanes = ARRAY_SIZE(tegra124_lanes), > .lanes = tegra124_lanes, > + .rx_wander = 0xf, > + .rx_eq = 0xf070, > + .cdr_cntl = 0x24, > + .dfe_cntl = 0x002008ee, > + .hs_slew = 0xe, > + .ls_rslew = {0x3, 0x0, 0x0}, > + .hs_discon_level = 0x5, > + .spare_in = 0x1, > + .hsic_port_offset = 6, > }; > > static const struct of_device_id tegra_xusb_padctl_of_match[] = { > @@ -864,6 +1991,80 @@ static const struct of_device_id tegra_xusb_padctl_of_match[] = { > }; > MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match); > > +static int tegra_xusb_read_fuse_calibration(struct tegra_xusb_padctl *padctl) > +{ > + unsigned int i; > + int err; > + u32 value; > + > + err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value); > + if (err < 0) > + return err; > + > + for (i = 0; i < TEGRA_XUSB_UTMI_PHYS; i++) { > + padctl->calib.hs_curr_level[i] = > + (value >> FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(i)) & > + FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK; > + } > + padctl->calib.hs_iref_cap = > + (value >> FUSE_SKU_CALIB_HS_IREF_CAP_SHIFT) & > + FUSE_SKU_CALIB_HS_IREF_CAP_MASK; > + padctl->calib.hs_term_range_adj = > + (value >> FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT) & > + FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK; > + padctl->calib.hs_squelch_level = > + (value >> FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_SHIFT) & > + FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_MASK; > + > + return 0; > +} > + > +static int tegra_xusb_setup_usb(struct tegra_xusb_padctl *padctl) > +{ > + struct phy *phy; > + unsigned int i; > + > + for (i = 0; i < TEGRA_XUSB_USB3_PHYS; i++) { > + phy = devm_phy_create(padctl->dev, NULL, &usb3_phy_ops, NULL); > + if (IS_ERR(phy)) > + return PTR_ERR(phy); > + > + padctl->phys[TEGRA_XUSB_PADCTL_USB3_P0 + i] = phy; > + phy_set_drvdata(phy, padctl); > + } > + > + for (i = 0; i < TEGRA_XUSB_UTMI_PHYS; i++) { > + char reg_name[sizeof("vbus-N")]; > + > + sprintf(reg_name, "vbus-%d", i); > + padctl->vbus[i] = devm_regulator_get(padctl->dev, reg_name); > + if (IS_ERR(padctl->vbus[i])) > + return PTR_ERR(padctl->vbus[i]); > + > + phy = devm_phy_create(padctl->dev, NULL, &utmi_phy_ops, NULL); > + if (IS_ERR(phy)) > + return PTR_ERR(phy); > + > + padctl->phys[TEGRA_XUSB_PADCTL_UTMI_P0 + i] = phy; > + phy_set_drvdata(phy, padctl); > + } > + > + padctl->vddio_hsic = devm_regulator_get(padctl->dev, "vddio-hsic"); > + if (IS_ERR(padctl->vddio_hsic)) > + return PTR_ERR(padctl->vddio_hsic); > + > + for (i = 0; i < TEGRA_XUSB_HSIC_PHYS; i++) { > + phy = devm_phy_create(padctl->dev, NULL, &hsic_phy_ops, NULL); > + if (IS_ERR(phy)) > + return PTR_ERR(phy); > + > + padctl->phys[TEGRA_XUSB_PADCTL_HSIC_P0 + i] = phy; > + phy_set_drvdata(phy, padctl); > + } > + > + return 0; > +} > + > static int tegra_xusb_padctl_probe(struct platform_device *pdev) > { > struct tegra_xusb_padctl *padctl; > @@ -888,6 +2089,10 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev) > if (IS_ERR(padctl->regs)) > return PTR_ERR(padctl->regs); > > + err = tegra_xusb_read_fuse_calibration(padctl); > + if (err < 0) > + return err; > + > padctl->rst = devm_reset_control_get(&pdev->dev, NULL); > if (IS_ERR(padctl->rst)) > return PTR_ERR(padctl->rst); > @@ -928,6 +2133,26 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev) > padctl->phys[TEGRA_XUSB_PADCTL_SATA] = phy; > phy_set_drvdata(phy, padctl); > > + INIT_WORK(&padctl->mbox_req_work, tegra_xusb_phy_mbox_work); > + padctl->mbox_client.dev = &pdev->dev; > + padctl->mbox_client.tx_block = true; > + padctl->mbox_client.tx_tout = 0; > + padctl->mbox_client.rx_callback = tegra_xusb_phy_mbox_rx; > + padctl->mbox_chan = mbox_request_channel(&padctl->mbox_client, 0); > + if (IS_ERR(padctl->mbox_chan)) { > + err = PTR_ERR(padctl->mbox_chan); > + if (err == -EPROBE_DEFER) { > + goto unregister; > + } else { > + dev_warn(&pdev->dev, > + "failed to get mailbox, USB support disabled"); > + } > + } else { > + err = tegra_xusb_setup_usb(padctl); > + if (err) > + goto unregister; > + } > + > padctl->provider = devm_of_phy_provider_register(&pdev->dev, > tegra_xusb_padctl_xlate); > if (IS_ERR(padctl->provider)) { > @@ -950,6 +2175,11 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev) > struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev); > int err; > > + if (!IS_ERR(padctl->mbox_chan)) { > + cancel_work_sync(&padctl->mbox_req_work); > + mbox_free_channel(padctl->mbox_chan); > + } > + > pinctrl_unregister(padctl->pinctrl); > > err = reset_control_assert(padctl->rst); > diff --git a/include/soc/tegra/xusb.h b/include/soc/tegra/xusb.h > index 5ce5e12..0136dc1 100644 > --- a/include/soc/tegra/xusb.h > +++ b/include/soc/tegra/xusb.h > @@ -10,6 +10,13 @@ > #ifndef __SOC_TEGRA_XUSB_H__ > #define __SOC_TEGRA_XUSB_H__ > > +#define TEGRA_XUSB_USB3_PHYS 2 > +#define TEGRA_XUSB_UTMI_PHYS 3 > +#define TEGRA_XUSB_HSIC_PHYS 2 > +#define TEGRA_XUSB_NUM_USB_PHYS (TEGRA_XUSB_USB3_PHYS + TEGRA_XUSB_UTMI_PHYS + \ > + TEGRA_XUSB_HSIC_PHYS) > +#define TEGRA_XUSB_NUM_PHYS (TEGRA_XUSB_NUM_USB_PHYS + 2) /* + SATA & PCIe */ > + > /* Command requests from the firmware */ > enum tegra_xusb_mbox_cmd { > MBOX_CMD_MSG_ENABLED = 1, > -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html