diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c index 1abc5913ec49..63711f6066c8 100644 --- a/drivers/phy/tegra/xusb-tegra210.c +++ b/drivers/phy/tegra/xusb-tegra210.c @@ -444,11 +444,55 @@ static const struct tegra_xusb_lane_map tegra210_usb3_map[] = { { 0, NULL, 0 } }; +static const struct tegra_xusb_lane_map tegra210b01_usb3_map[] = { + { 0, "pcie", 5 }, + { 1, "pcie", 4 }, + { 2, "pcie", 1 }, + { 0, NULL, 0 } +}; + +static inline bool plle_hw_sequence_is_enabled(struct tegra_xusb_padctl *padctl) { + bool is_t210b01 = padctl->soc == &tegra210b01_xusb_padctl_soc; + + if (is_t210b01) + return tegra210b01_plle_hw_sequence_is_enabled(); + + return tegra210_plle_hw_sequence_is_enabled(); +} + +static inline int plle_hw_sequence_start(struct tegra_xusb_padctl *padctl) { + bool is_t210b01 = padctl->soc == &tegra210b01_xusb_padctl_soc; + + if (is_t210b01) + return tegra210b01_plle_hw_sequence_start(); + + return tegra210_plle_hw_sequence_start(); +} + +static inline void xusb_pll_hw_control_enable(struct tegra_xusb_padctl *padctl) { + bool is_t210b01 = padctl->soc == &tegra210b01_xusb_padctl_soc; + + if (is_t210b01) + tegra210b01_xusb_pll_hw_control_enable(); + else + tegra210_xusb_pll_hw_control_enable(); +} + +static inline void xusb_pll_hw_sequence_start(struct tegra_xusb_padctl *padctl) { + bool is_t210b01 = padctl->soc == &tegra210b01_xusb_padctl_soc; + + if (is_t210b01) + tegra210b01_xusb_pll_hw_sequence_start(); + else + tegra210_xusb_pll_hw_sequence_start(); +} + static int tegra210_usb3_lane_map(struct tegra_xusb_lane *lane) { const struct tegra_xusb_lane_map *map; + bool is_t210b01 = lane->pad->padctl->soc == &tegra210b01_xusb_padctl_soc; - for (map = tegra210_usb3_map; map->type; map++) { + for (map = is_t210b01 ? tegra210b01_usb3_map : tegra210_usb3_map; map->type; map++) { if (map->index == lane->index && strcmp(map->type, lane->pad->soc->name) == 0) { dev_dbg(lane->pad->padctl->dev, "lane = %s map to port = usb3-%d\n", @@ -476,7 +520,13 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl) if (err < 0) return err; - if (tegra210_plle_hw_sequence_is_enabled()) + if (pcie->uphy_mgmt) { + err = clk_prepare_enable(pcie->uphy_mgmt); + if (err < 0) + goto disable_pll; + } + + if (plle_hw_sequence_is_enabled(padctl)) goto skip_pll_init; err = reset_control_deassert(pcie->rst); @@ -643,7 +693,7 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl) value &= ~XUSB_PADCTL_UPHY_PLL_CTL8_RCAL_CLK_EN; padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8); - tegra210_xusb_pll_hw_control_enable(); + xusb_pll_hw_control_enable(padctl); value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); value &= ~XUSB_PADCTL_UPHY_PLL_CTL1_PWR_OVRD; @@ -659,7 +709,7 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl) usleep_range(10, 20); - tegra210_xusb_pll_hw_sequence_start(); + xusb_pll_hw_sequence_start(padctl); skip_pll_init: pcie->enable = true; @@ -675,6 +725,9 @@ skip_pll_init: reset: reset_control_assert(pcie->rst); disable: + if (pcie->uphy_mgmt) + clk_disable_unprepare(pcie->uphy_mgmt); +disable_pll: clk_disable_unprepare(pcie->pll); return err; } @@ -696,6 +749,9 @@ static void tegra210_pex_uphy_disable(struct tegra_xusb_padctl *padctl) padctl_writel(padctl, value, XUSB_PADCTL_USB3_PAD_MUX); } + if (pcie->uphy_mgmt) + clk_disable_unprepare(pcie->uphy_mgmt); + clk_disable_unprepare(pcie->pll); } @@ -716,7 +772,7 @@ static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl) if (IS_ERR(lane)) return 0; - if (tegra210_plle_hw_sequence_is_enabled()) + if (plle_hw_sequence_is_enabled(padctl)) goto skip_pll_init; usb = tegra_xusb_lane_check(lane, "usb3-ss"); @@ -1008,8 +1064,8 @@ static int tegra210_uphy_init(struct tegra_xusb_padctl *padctl) if (padctl->sata) tegra210_sata_uphy_enable(padctl); - if (!tegra210_plle_hw_sequence_is_enabled()) - tegra210_plle_hw_sequence_start(); + if (!plle_hw_sequence_is_enabled(padctl)) + plle_hw_sequence_start(padctl); else dev_dbg(padctl->dev, "PLLE is already in HW control\n"); @@ -2559,6 +2615,15 @@ static const struct tegra_xusb_lane_soc tegra210_pcie_lanes[] = { TEGRA210_UPHY_LANE("pcie-6", 0x028, 24, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(6)), }; +static const struct tegra_xusb_lane_soc tegra210b01_pcie_lanes[] = { + 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)), +}; + static struct tegra_xusb_usb3_port * tegra210_lane_to_usb3_port(struct tegra_xusb_lane *lane) { @@ -2785,6 +2850,7 @@ tegra210_pcie_pad_probe(struct tegra_xusb_padctl *padctl, struct tegra_xusb_pcie_pad *pcie; struct tegra_xusb_pad *pad; int err; + bool is_t210b01 = padctl->soc == &tegra210b01_xusb_padctl_soc; pcie = kzalloc_obj(*pcie); if (!pcie) @@ -2807,6 +2873,15 @@ tegra210_pcie_pad_probe(struct tegra_xusb_padctl *padctl, goto unregister; } + if (is_t210b01) { + pcie->uphy_mgmt = devm_clk_get(&pad->dev, "uphy_mgmt"); + if (IS_ERR(pcie->uphy_mgmt)) { + err = PTR_ERR(pcie->uphy_mgmt); + dev_err(&pad->dev, "failed to get uphy mgmt clock: %d\n", err); + goto unregister; + } + } + pcie->rst = devm_reset_control_get(&pad->dev, "phy"); if (IS_ERR(pcie->rst)) { err = PTR_ERR(pcie->rst); @@ -2847,6 +2922,13 @@ static const struct tegra_xusb_pad_soc tegra210_pcie_pad = { .ops = &tegra210_pcie_ops, }; +static const struct tegra_xusb_pad_soc tegra210b01_pcie_pad = { + .name = "pcie", + .num_lanes = ARRAY_SIZE(tegra210b01_pcie_lanes), + .lanes = tegra210b01_pcie_lanes, + .ops = &tegra210_pcie_ops, +}; + static const struct tegra_xusb_lane_soc tegra210_sata_lanes[] = { TEGRA210_UPHY_LANE("sata-0", 0x028, 30, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2), }; @@ -3016,6 +3098,11 @@ static const struct tegra_xusb_pad_soc * const tegra210_pads[] = { &tegra210_sata_pad, }; +static const struct tegra_xusb_pad_soc * const tegra210b01_pads[] = { + &tegra210_usb2_pad, + &tegra210b01_pcie_pad, +}; + static int tegra210_usb2_port_enable(struct tegra_xusb_port *port) { return 0; @@ -3076,6 +3163,12 @@ tegra210_usb3_port_map(struct tegra_xusb_port *port) return tegra_xusb_port_find_lane(port, tegra210_usb3_map, "usb3-ss"); } +static struct tegra_xusb_lane * +tegra210b01_usb3_port_map(struct tegra_xusb_port *port) +{ + return tegra_xusb_port_find_lane(port, tegra210b01_usb3_map, "usb3-ss"); +} + static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = { .release = tegra_xusb_usb3_port_release, .enable = tegra210_usb3_port_enable, @@ -3083,6 +3176,13 @@ static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = { .map = tegra210_usb3_port_map, }; +static const struct tegra_xusb_port_ops tegra210b01_usb3_port_ops = { + .release = tegra_xusb_usb3_port_release, + .enable = tegra210_usb3_port_enable, + .disable = tegra210_usb3_port_disable, + .map = tegra210b01_usb3_port_map, +}; + static int tegra210_utmi_port_reset(struct phy *phy) { struct tegra_xusb_padctl *padctl; @@ -3294,6 +3394,26 @@ const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc = { }; EXPORT_SYMBOL_GPL(tegra210_xusb_padctl_soc); +const struct tegra_xusb_padctl_soc tegra210b01_xusb_padctl_soc = { + .num_pads = ARRAY_SIZE(tegra210b01_pads), + .pads = tegra210b01_pads, + .ports = { + .usb2 = { + .ops = &tegra210_usb2_port_ops, + .count = 4, + }, + .usb3 = { + .ops = &tegra210b01_usb3_port_ops, + .count = 4, + }, + }, + .ops = &tegra210_xusb_padctl_ops, + .supply_names = tegra210_xusb_padctl_supply_names, + .num_supplies = ARRAY_SIZE(tegra210_xusb_padctl_supply_names), + .need_fake_usb3_port = true, +}; +EXPORT_SYMBOL_GPL(tegra210b01_xusb_padctl_soc); + MODULE_AUTHOR("Andrew Bresticker "); MODULE_DESCRIPTION("NVIDIA Tegra 210 XUSB Pad Controller driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index 9d74c0ecc31b..f2902b85f6ec 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c @@ -59,6 +59,10 @@ static const struct of_device_id tegra_xusb_padctl_of_match[] = { .compatible = "nvidia,tegra210-xusb-padctl", .data = &tegra210_xusb_padctl_soc, }, + { + .compatible = "nvidia,tegra210b01-xusb-padctl", + .data = &tegra210b01_xusb_padctl_soc, + }, #endif #if defined(CONFIG_ARCH_TEGRA_186_SOC) { diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h index 77609e54de66..5782f4246c9e 100644 --- a/drivers/phy/tegra/xusb.h +++ b/drivers/phy/tegra/xusb.h @@ -243,6 +243,7 @@ struct tegra_xusb_pcie_pad { struct reset_control *rst; struct clk *pll; + struct clk *uphy_mgmt; bool enable; }; @@ -504,6 +505,7 @@ extern const struct tegra_xusb_padctl_soc tegra124_xusb_padctl_soc; #endif #if defined(CONFIG_ARCH_TEGRA_210_SOC) extern const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc; +extern const struct tegra_xusb_padctl_soc tegra210b01_xusb_padctl_soc; #endif #if defined(CONFIG_ARCH_TEGRA_186_SOC) extern const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc;