diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c index 06b587f84270..cc8caad54192 100644 --- a/drivers/phy/tegra/xusb-tegra210.c +++ b/drivers/phy/tegra/xusb-tegra210.c @@ -230,6 +230,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_MISC_PAD_PX_CTL8(x) (0x460 + (x) * (0x1c)) +#define CFG_ADDR(x) (((x) & 0xff) << 16) +#define CFG_WDATA(x) (((x) & 0xffff) << 0) +#define CFG_RESET (1 << 27) +#define CFG_WS (1 << 24) + #define XUSB_PADCTL_UPHY_PLL_S0_CTL1 0x860 #define XUSB_PADCTL_UPHY_PLL_S0_CTL2 0x864 @@ -240,6 +246,8 @@ #define XUSB_PADCTL_UPHY_PLL_S0_CTL8 0x87c +#define XUSB_PADCTL_UPHY_PLL_S0_CTL10 0x384 + #define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1 0x960 #define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2 0x964 @@ -407,6 +415,18 @@ #define UHSIC_STROBE_RPD_C BIT(16) #define UHSIC_STROBE_RPD_D BIT(24) +struct init_data { + u8 cfg_addr; + u16 cfg_wdata; +}; + +static struct init_data usb3_pll_g1_init_data[] = { + {.cfg_addr = 0x2, .cfg_wdata = 0x0000}, + {.cfg_addr = 0x3, .cfg_wdata = 0x7051}, + {.cfg_addr = 0x25, .cfg_wdata = 0x0130}, + {.cfg_addr = 0x1E, .cfg_wdata = 0x0017}, +}; + struct tegra210_xusb_fuse_calibration { u32 hs_curr_level[4]; u32 hs_term_range_adj; @@ -444,11 +464,38 @@ 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 int t210b01_compatible(struct tegra_xusb_padctl *padctl) +{ + struct device_node *np; + const char *compatible; + + np = padctl->dev->of_node; + compatible = of_get_property(np, "compatible", NULL); + + if (!compatible) { + dev_err(padctl->dev, "Failed to get compatible property\n"); + return -ENODEV; + } + + if (strstr(compatible, "tegra210b01") != NULL) + return 1; + return 0; +} + static int tegra210_usb3_lane_map(struct tegra_xusb_lane *lane) { const struct tegra_xusb_lane_map *map; - for (map = tegra210_usb3_map; map->type; map++) { + for (map = t210b01_compatible(lane->pad->padctl) ? + 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,6 +523,12 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl) if (err < 0) return err; + if (t210b01_compatible(padctl) == 1) { + err = clk_prepare_enable(pcie->uphy_mgmt_clk); + if (err < 0) + return err; + } + if (tegra210_plle_hw_sequence_is_enabled()) goto skip_pll_init; @@ -483,6 +536,18 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl) if (err < 0) goto disable; + if (t210b01_compatible(padctl) == 1) { + for (i = 0; i < ARRAY_SIZE(usb3_pll_g1_init_data); i++) { + value = 0; + value |= CFG_ADDR(usb3_pll_g1_init_data[i].cfg_addr); + value |= CFG_WDATA(usb3_pll_g1_init_data[i].cfg_wdata); + value |= CFG_RESET; + value |= CFG_WS; + padctl_writel(padctl, value, + XUSB_PADCTL_UPHY_PLL_S0_CTL10); + } + } + value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); value &= ~(XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK << XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT); @@ -676,6 +741,8 @@ reset: reset_control_assert(pcie->rst); disable: clk_disable_unprepare(pcie->pll); + if (t210b01_compatible(padctl) == 1) + clk_disable_unprepare(pcie->uphy_mgmt_clk); return err; } @@ -697,6 +764,8 @@ static void tegra210_pex_uphy_disable(struct tegra_xusb_padctl *padctl) } clk_disable_unprepare(pcie->pll); + if (t210b01_compatible(padctl) == 1) + clk_disable_unprepare(pcie->uphy_mgmt_clk); } /* must be called under padctl->lock */ @@ -2560,12 +2629,12 @@ static const struct tegra_xusb_lane_soc tegra210_pcie_lanes[] = { }; 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)), + TEGRA210_UPHY_LANE("pcie-0", 0x28, 12, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)), + TEGRA210_UPHY_LANE("pcie-1", 0x28, 14, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)), + TEGRA210_UPHY_LANE("pcie-2", 0x28, 16, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)), + TEGRA210_UPHY_LANE("pcie-3", 0x28, 18, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)), + TEGRA210_UPHY_LANE("pcie-4", 0x28, 20, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)), + TEGRA210_UPHY_LANE("pcie-5", 0x28, 22, 0x3, pcie, XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL2(0)), }; static struct tegra_xusb_usb3_port * @@ -2816,6 +2885,15 @@ tegra210_pcie_pad_probe(struct tegra_xusb_padctl *padctl, goto unregister; } + if (t210b01_compatible(padctl) == 1) { + pcie->uphy_mgmt_clk = devm_clk_get(&pad->dev, "uphy_mgmt"); + if (IS_ERR(pcie->uphy_mgmt_clk)) { + err = PTR_ERR(pcie->uphy_mgmt_clk); + dev_err(&pad->dev, + "failed to get uphy_mgmt_clk clock: %d\n", err); + } + } + pcie->rst = devm_reset_control_get(&pad->dev, "phy"); if (IS_ERR(pcie->rst)) { err = PTR_ERR(pcie->rst); @@ -3094,7 +3172,16 @@ static void tegra210_usb3_port_disable(struct tegra_xusb_port *port) static struct tegra_xusb_lane * tegra210_usb3_port_map(struct tegra_xusb_port *port) { - return tegra_xusb_port_find_lane(port, tegra210_usb3_map, "usb3-ss"); + int err = t210b01_compatible(port->padctl); + + if (err == 1) + return tegra_xusb_port_find_lane(port, + tegra210b01_usb3_map, "usb3-ss"); + else if (err == 0) + return tegra_xusb_port_find_lane(port, + tegra210_usb3_map, "usb3-ss"); + else + return NULL; } static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = { @@ -3287,6 +3374,14 @@ static const char * const tegra210_xusb_padctl_supply_names[] = { "hvdd-pex-pll-e", }; +static const char * const tegra210b01_supply_names[] = { + "avdd_pll_uerefe", + "hvdd_pex_pll_e", + "dvdd_pex_pll", + "hvddio_pex", + "dvddio_pex", +}; + const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc = { .num_pads = ARRAY_SIZE(tegra210_pads), .pads = tegra210_pads, @@ -3325,8 +3420,8 @@ const struct tegra_xusb_padctl_soc tegra210b01_xusb_padctl_soc = { }, }, .ops = &tegra210_xusb_padctl_ops, - .supply_names = tegra210_xusb_padctl_supply_names, - .num_supplies = ARRAY_SIZE(tegra210_xusb_padctl_supply_names), + .supply_names = tegra210b01_supply_names, + .num_supplies = ARRAY_SIZE(tegra210b01_supply_names), .need_fake_usb3_port = true, }; EXPORT_SYMBOL_GPL(tegra210b01_xusb_padctl_soc);