Skip to content

Commit

Permalink
phy: tegra: xusb: Add Tegra210 lane_iddq operation
Browse files Browse the repository at this point in the history
As per Tegra210 TRM, before changing lane assignments, driver should
keep lanes in IDDQ and sleep state; after changing lane assignments,
driver should bring lanes out of IDDQ.
This commit implements the required operations.

Signed-off-by: JC Kuo <[email protected]>
Acked-By: Vinod Koul <[email protected]>
Signed-off-by: Thierry Reding <[email protected]>
  • Loading branch information
jckuo authored and thierryreding committed Jun 3, 2021
1 parent 2352fdb commit c339605
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 8 deletions.
82 changes: 74 additions & 8 deletions drivers/phy/tegra/xusb-tegra210.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,18 @@
#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_PX_CTL2(x) (0x464 + (x) * 0x40)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ BIT(0)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD BIT(1)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK GENMASK(5, 4)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL GENMASK(5, 4)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD BIT(24)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ BIT(8)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD BIT(9)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK GENMASK(13, 12)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL GENMASK(13, 12)
#define XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD BIT(25)

#define XUSB_PADCTL_UPHY_PLL_S0_CTL1 0x860

#define XUSB_PADCTL_UPHY_PLL_S0_CTL2 0x864
Expand All @@ -209,6 +221,7 @@
#define XUSB_PADCTL_UPHY_PLL_S0_CTL8 0x87c

#define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1 0x960
#define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2 0x964

#define XUSB_PADCTL_UPHY_USB3_PADX_ECTL1(x) (0xa60 + (x) * 0x40)
#define XUSB_PADCTL_UPHY_USB3_PAD_ECTL1_TX_TERM_CTRL_SHIFT 16
Expand Down Expand Up @@ -1640,6 +1653,55 @@ static const struct tegra_xusb_pad_soc tegra210_hsic_pad = {
.ops = &tegra210_hsic_ops,
};

static void tegra210_uphy_lane_iddq_enable(struct tegra_xusb_lane *lane)
{
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
u32 value;

value = padctl_readl(padctl, lane->soc->regs.misc_ctl2);
value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD;
value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD;
value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD;
value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD;
value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ;
value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK;
value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL;
value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ;
value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK;
value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL;
padctl_writel(padctl, value, lane->soc->regs.misc_ctl2);
}

static void tegra210_uphy_lane_iddq_disable(struct tegra_xusb_lane *lane)
{
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
u32 value;

value = padctl_readl(padctl, lane->soc->regs.misc_ctl2);
value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ_OVRD;
value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ_OVRD;
value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_PWR_OVRD;
value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_PWR_OVRD;
value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_IDDQ;
value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_MASK;
value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_TX_SLEEP_VAL;
value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_IDDQ;
value &= ~XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_MASK;
value |= XUSB_PADCTL_UPHY_MISC_PAD_CTL2_RX_SLEEP_VAL;
padctl_writel(padctl, value, lane->soc->regs.misc_ctl2);
}

#define TEGRA210_UPHY_LANE(_name, _offset, _shift, _mask, _type, _misc) \
{ \
.name = _name, \
.offset = _offset, \
.shift = _shift, \
.mask = _mask, \
.num_funcs = ARRAY_SIZE(tegra210_##_type##_functions), \
.funcs = tegra210_##_type##_functions, \
.regs.misc_ctl2 = _misc, \
}

static const char *tegra210_pcie_functions[] = {
"pcie-x1",
"usb3-ss",
Expand All @@ -1648,13 +1710,13 @@ static const char *tegra210_pcie_functions[] = {
};

static const struct tegra_xusb_lane_soc tegra210_pcie_lanes[] = {
TEGRA210_LANE("pcie-0", 0x028, 12, 0x3, pcie),
TEGRA210_LANE("pcie-1", 0x028, 14, 0x3, pcie),
TEGRA210_LANE("pcie-2", 0x028, 16, 0x3, pcie),
TEGRA210_LANE("pcie-3", 0x028, 18, 0x3, pcie),
TEGRA210_LANE("pcie-4", 0x028, 20, 0x3, pcie),
TEGRA210_LANE("pcie-5", 0x028, 22, 0x3, pcie),
TEGRA210_LANE("pcie-6", 0x028, 24, 0x3, pcie),
TEGRA210_UPHY_LANE("pcie-0", 0x028, 12, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)),
TEGRA210_UPHY_LANE("pcie-1", 0x028, 14, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(1)),
TEGRA210_UPHY_LANE("pcie-2", 0x028, 16, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(2)),
TEGRA210_UPHY_LANE("pcie-3", 0x028, 18, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(3)),
TEGRA210_UPHY_LANE("pcie-4", 0x028, 20, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(4)),
TEGRA210_UPHY_LANE("pcie-5", 0x028, 22, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(5)),
TEGRA210_UPHY_LANE("pcie-6", 0x028, 24, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(6)),
};

static struct tegra_xusb_usb3_port *
Expand Down Expand Up @@ -1815,6 +1877,8 @@ static void tegra210_pcie_lane_remove(struct tegra_xusb_lane *lane)
static const struct tegra_xusb_lane_ops tegra210_pcie_lane_ops = {
.probe = tegra210_pcie_lane_probe,
.remove = tegra210_pcie_lane_remove,
.iddq_enable = tegra210_uphy_lane_iddq_enable,
.iddq_disable = tegra210_uphy_lane_iddq_disable,
};

static int tegra210_pcie_phy_init(struct phy *phy)
Expand Down Expand Up @@ -1939,7 +2003,7 @@ static const struct tegra_xusb_pad_soc tegra210_pcie_pad = {
};

static const struct tegra_xusb_lane_soc tegra210_sata_lanes[] = {
TEGRA210_LANE("sata-0", 0x028, 30, 0x3, pcie),
TEGRA210_UPHY_LANE("sata-0", 0x028, 30, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2),
};

static struct tegra_xusb_lane *
Expand Down Expand Up @@ -1978,6 +2042,8 @@ static void tegra210_sata_lane_remove(struct tegra_xusb_lane *lane)
static const struct tegra_xusb_lane_ops tegra210_sata_lane_ops = {
.probe = tegra210_sata_lane_probe,
.remove = tegra210_sata_lane_remove,
.iddq_enable = tegra210_uphy_lane_iddq_enable,
.iddq_disable = tegra210_uphy_lane_iddq_disable,
};

static int tegra210_sata_phy_init(struct phy *phy)
Expand Down
6 changes: 6 additions & 0 deletions drivers/phy/tegra/xusb.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,11 +321,17 @@ static void tegra_xusb_lane_program(struct tegra_xusb_lane *lane)
if (soc->num_funcs < 2)
return;

if (lane->pad->ops->iddq_enable)
lane->pad->ops->iddq_enable(lane);

/* choose function */
value = padctl_readl(padctl, soc->offset);
value &= ~(soc->mask << soc->shift);
value |= lane->function << soc->shift;
padctl_writel(padctl, value, soc->offset);

if (lane->pad->ops->iddq_disable)
lane->pad->ops->iddq_disable(lane);
}

static void tegra_xusb_pad_program(struct tegra_xusb_pad *pad)
Expand Down
6 changes: 6 additions & 0 deletions drivers/phy/tegra/xusb.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ struct tegra_xusb_lane_soc {

const char * const *funcs;
unsigned int num_funcs;

struct {
unsigned int misc_ctl2;
} regs;
};

struct tegra_xusb_lane {
Expand Down Expand Up @@ -126,6 +130,8 @@ struct tegra_xusb_lane_ops {
struct device_node *np,
unsigned int index);
void (*remove)(struct tegra_xusb_lane *lane);
void (*iddq_enable)(struct tegra_xusb_lane *lane);
void (*iddq_disable)(struct tegra_xusb_lane *lane);
};

bool tegra_xusb_lane_check(struct tegra_xusb_lane *lane, const char *function);
Expand Down

0 comments on commit c339605

Please sign in to comment.