platform: tegra: padctl: add receiver detector API
Mark Kuo [Mon, 23 May 2016 09:52:37 +0000 (17:52 +0800)]
Support clamp_en_early and receiver detector controls.

A copy of JC's original work at http://git-master/r/#/c/1141282/3 on
tegra_usb_pad_ctrl.c

Bug 200162414
Bug 200179626

Change-Id: I8a29f7d90bfedaaa1b2609f46f511754eaa1e71f
Signed-off-by: Mark Kuo <mkuo@nvidia.com>
Reviewed-on: http://git-master/r/1169994
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: ChihMin Cheng <ccheng@nvidia.com>
Reviewed-by: Ashutosh Jha <ajha@nvidia.com>

arch/arm/mach-tegra/include/mach/tegra_usb_pad_ctrl.h
drivers/platform/tegra/tegra_usb_pad_ctrl.c

index 0fc8a00..193efac 100644 (file)
@@ -138,11 +138,23 @@ static inline enum padctl_lane usb3_laneowner_to_lane_enum(u8 laneowner)
 #define S0_CTL8_PLL0_RCAL_OVRD                         (1 << 15)
 #define S0_CTL8_PLL0_RCAL_DONE                         (1 << 31)
 
+#define XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL1(x)   (0x460 + ((x) * 0x40))
 #define XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL1      0x460
 #define XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL1_AUX_RX_IDLE_TH_MASK  (0x3 << 24)
 #define XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL1_AUX_RX_IDLE_TH       (1 << 24)
 #define XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL1_AUX_TX_RDET_STATUS   (1 << 7)
 
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_SHIFT 20
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_MASK 0x3
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_IDLE_MODE_VAL 0x1
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_TERM_EN BIT(18)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_RX_MODE_OVRD BIT(13)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_TX_MODE_OVRD BIT(12)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_TX_RDET_CLK_EN BIT(6)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_TX_RDET_BYP BIT(5)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_TX_RDET_EN BIT(4)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_TX_TERM_EN BIT(2)
+
 #define XUSB_PADCTL_UPHY_MISC_PAD_P1_CTL1      0x4A0
 #define XUSB_PADCTL_UPHY_MISC_PAD_P1_CTL1_AUX_TX_RDET_STATUS   (1 << 7)
 
@@ -155,6 +167,7 @@ static inline enum padctl_lane usb3_laneowner_to_lane_enum(u8 laneowner)
 #define XUSB_PADCTL_UPHY_MISC_PAD_P4_CTL1      0x560
 #define XUSB_PADCTL_UPHY_MISC_PAD_P4_CTL1_AUX_TX_RDET_STATUS   (1 << 7)
 
+#define XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(x)   (0x464 + ((x) * 0x40))
 #define XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL2      0x464
 #define XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL2_TX_IDDQ      (1 << 0)
 #define XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL2_RX_IDDQ      (1 << 8)
@@ -164,6 +177,10 @@ static inline enum padctl_lane usb3_laneowner_to_lane_enum(u8 laneowner)
 #define XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL2_RX_SLEEP     (3 << 12)
 #define XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL2_TX_PWR_OVRD  (1 << 24)
 #define XUSB_PADCTL_UPHY_MISC_PAD_P0_CTL2_RX_PWR_OVRD  (1 << 25)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD (1 << 9)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ (1 << 8)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD (1 << 1)
+#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ (1 << 0)
 
 #define XUSB_PADCTL_UPHY_MISC_PAD_P1_CTL2      0x4A4
 #define XUSB_PADCTL_UPHY_MISC_PAD_P2_CTL2      0x4E4
@@ -171,6 +188,8 @@ static inline enum padctl_lane usb3_laneowner_to_lane_enum(u8 laneowner)
 #define XUSB_PADCTL_UPHY_MISC_PAD_P4_CTL2      0x564
 #define XUSB_PADCTL_UPHY_MISC_PAD_P5_CTL2      0x5A4
 #define XUSB_PADCTL_UPHY_MISC_PAD_P6_CTL2      0x5E4
+
+#define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1      0x960
 #define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2      0x964
 
 #define XUSB_PADCTL_UPHY_PLL_S0_CTL_1_0 0x860
@@ -247,6 +266,7 @@ static inline enum padctl_lane usb3_laneowner_to_lane_enum(u8 laneowner)
 
 #define XUSB_PADCTL_ELPG_PROGRAM_0             0x20
 #define XUSB_PADCTL_ELPG_PROGRAM_1             0x24
+#define SSPX_ELPG_CLAMP_EN_EARLY(x)           (1 << ((x)*3 + 1))
 #define SSP0_ELPG_CLAMP_EN                     (1 << 0)
 #define SSP0_ELPG_CLAMP_EN_EARLY       (1 << 1)
 #define SSP0_ELPG_VCORE_DOWN           (1 << 2)
@@ -686,4 +706,9 @@ void xusb_utmi_pad_driver_power(int port, bool on);
 int tegra_padctl_init_sata_pad(void);
 int tegra_padctl_enable_sata_pad(bool enable);
 
+#ifdef CONFIG_ARCH_TEGRA_21x_SOC
+void t210_receiver_detector(unsigned port, bool on);
+void t210_clamp_en_early(unsigned port, bool on);
+#endif
+
 #endif
index c7c9c02..a0869ae 100644 (file)
@@ -84,6 +84,7 @@ struct tegra_padctl {
        u32 lane_map; /* used for PCIE lanes */
        bool enable_sata_port; /* used for SATA lane */
 };
+static struct tegra_padctl *padctl;
 #endif
 
 void tegra_xhci_release_otg_port(bool release)
@@ -2513,7 +2514,6 @@ tegra_padctl_probe(struct platform_device *pdev)
        bool enable_sata_port;
        int err = 0;
        const struct of_device_id *match;
-       struct tegra_padctl *padctl;
        struct clk *plle_clk;
        struct clk *plle_hw_clk;
 
@@ -2632,6 +2632,99 @@ static int __init tegra_xusb_padctl_init(void)
 }
 fs_initcall(tegra_xusb_padctl_init);
 
+#define reg_dump(_name, _reg) \
+       pr_debug("%s @%x = 0x%x\n", #_name, (_reg), \
+                ioread32(IO_ADDRESS(TEGRA_XUSB_PADCTL_BASE) + (_reg)))
+static bool clamp_en_early_enabled[4] = {false};
+void t210_clamp_en_early(unsigned port, bool on)
+{
+       u32 mask;
+
+       if ((on && clamp_en_early_enabled[port]) ||
+                       (!on && !clamp_en_early_enabled[port]))
+               return;
+
+       clamp_en_early_enabled[port] = on;
+       pr_debug("%s %s SS port %d\n", __func__,
+                       on ? "enable" : "disable", port);
+
+       mask = SSPX_ELPG_CLAMP_EN_EARLY(port);
+       if (on) {
+               tegra_usb_pad_reg_update(XUSB_PADCTL_ELPG_PROGRAM_1, 0, mask);
+               udelay(60);
+       } else
+               tegra_usb_pad_reg_update(XUSB_PADCTL_ELPG_PROGRAM_1, mask, 0);
+
+       reg_dump("elpg_program1", XUSB_PADCTL_ELPG_PROGRAM_1);
+}
+EXPORT_SYMBOL_GPL(t210_clamp_en_early);
+
+static bool receiver_detector_disabled[4] = {false};
+void t210_receiver_detector(unsigned port, bool on)
+{
+       u8 lane;
+       enum padctl_lane lane_enum;
+       u32 misc_pad_ctl1, misc_pad_ctl2;
+       u32 mask;
+
+       if (!padctl)
+               return;
+
+       lane = (padctl->lane_owner >> (port * 4)) & 0xf;
+       lane_enum = usb3_laneowner_to_lane_enum(lane);
+       if ((lane == USB3_LANE_NOT_ENABLED) || (lane_enum < 0))
+               return;
+
+       if ((on && !receiver_detector_disabled[port]) ||
+                       (!on && receiver_detector_disabled[port]))
+               return;
+
+       receiver_detector_disabled[port] = !on;
+
+       if (lane_enum == SATA_S0) {
+               misc_pad_ctl1 = XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1;
+               misc_pad_ctl2 = XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2;
+       } else {
+               misc_pad_ctl1 = XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL1(lane_enum);
+               misc_pad_ctl2 = XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(lane_enum);
+       }
+
+       pr_debug("%s %s SS port %d lane %d CTL1 addr 0x%x CTL2 addr 0x%x\n",
+               __func__, on ? "enable" : "disable", port, lane_enum,
+               misc_pad_ctl1, misc_pad_ctl2);
+
+       if (!on) {
+               mask = XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ |
+                       XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ;
+               tegra_usb_pad_reg_update(misc_pad_ctl2, mask, 0);
+
+               mask = XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD |
+                       XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD;
+               tegra_usb_pad_reg_update(misc_pad_ctl2, 0, mask);
+
+               mask = (XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_TX_RDET_CLK_EN |
+                       XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_TX_RDET_BYP |
+                       XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_TX_RDET_EN |
+                       XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_TX_TERM_EN);
+               tegra_usb_pad_reg_update(misc_pad_ctl1, mask, 0);
+
+               mask = XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_TX_MODE_OVRD;
+               tegra_usb_pad_reg_update(misc_pad_ctl1, 0, mask);
+       } else {
+               mask = XUSB_PADCTL_UPHY_MISC_PAD_CTL1_AUX_TX_MODE_OVRD;
+               tegra_usb_pad_reg_update(misc_pad_ctl1, mask, 0);
+
+               mask = XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD |
+                       XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD;
+               tegra_usb_pad_reg_update(misc_pad_ctl2, mask, 0);
+       }
+
+       reg_dump("ctrl1", misc_pad_ctl1);
+       reg_dump("ctrl2", misc_pad_ctl2);
+       reg_dump("elpg_program1", XUSB_PADCTL_ELPG_PROGRAM_1);
+}
+EXPORT_SYMBOL_GPL(t210_receiver_detector);
+
 #else
 
 /* save restore below pad control register when cross LP0 */