|
@@ -36,7 +36,6 @@
|
|
|
#define DRV_NAME "tegra-ehci"
|
|
|
|
|
|
static struct hc_driver __read_mostly tegra_ehci_hc_driver;
|
|
|
-static bool usb1_reset_attempted;
|
|
|
|
|
|
struct tegra_ehci_soc_config {
|
|
|
bool has_hostpc;
|
|
@@ -51,67 +50,54 @@ struct tegra_ehci_hcd {
|
|
|
enum tegra_usb_phy_port_speed port_speed;
|
|
|
};
|
|
|
|
|
|
-/*
|
|
|
- * The 1st USB controller contains some UTMI pad registers that are global for
|
|
|
- * all the controllers on the chip. Those registers are also cleared when
|
|
|
- * reset is asserted to the 1st controller. This means that the 1st controller
|
|
|
- * can only be reset when no other controlled has finished probing. So we'll
|
|
|
- * reset the 1st controller before doing any other setup on any of the
|
|
|
- * controllers, and then never again.
|
|
|
- *
|
|
|
- * Since this is a PHY issue, the Tegra PHY driver should probably be doing
|
|
|
- * the resetting of the USB controllers. But to keep compatibility with old
|
|
|
- * device trees that don't have reset phandles in the PHYs, do it here.
|
|
|
- * Those old DTs will be vulnerable to total USB breakage if the 1st EHCI
|
|
|
- * device isn't the first one to finish probing, so warn them.
|
|
|
- */
|
|
|
static int tegra_reset_usb_controller(struct platform_device *pdev)
|
|
|
{
|
|
|
struct device_node *phy_np;
|
|
|
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
|
|
struct tegra_ehci_hcd *tegra =
|
|
|
(struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv;
|
|
|
- bool has_utmi_pad_registers = false;
|
|
|
+ struct reset_control *rst;
|
|
|
+ int err;
|
|
|
|
|
|
phy_np = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0);
|
|
|
if (!phy_np)
|
|
|
return -ENOENT;
|
|
|
|
|
|
- if (of_property_read_bool(phy_np, "nvidia,has-utmi-pad-registers"))
|
|
|
- has_utmi_pad_registers = true;
|
|
|
+ /*
|
|
|
+ * The 1st USB controller contains some UTMI pad registers that are
|
|
|
+ * global for all the controllers on the chip. Those registers are
|
|
|
+ * also cleared when reset is asserted to the 1st controller.
|
|
|
+ */
|
|
|
+ rst = of_reset_control_get_shared(phy_np, "utmi-pads");
|
|
|
+ if (IS_ERR(rst)) {
|
|
|
+ dev_warn(&pdev->dev,
|
|
|
+ "can't get utmi-pads reset from the PHY\n");
|
|
|
+ dev_warn(&pdev->dev,
|
|
|
+ "continuing, but please update your DT\n");
|
|
|
+ } else {
|
|
|
+ /*
|
|
|
+ * PHY driver performs UTMI-pads reset in a case of
|
|
|
+ * non-legacy DT.
|
|
|
+ */
|
|
|
+ reset_control_put(rst);
|
|
|
+ }
|
|
|
|
|
|
- if (!usb1_reset_attempted) {
|
|
|
- struct reset_control *usb1_reset;
|
|
|
+ of_node_put(phy_np);
|
|
|
|
|
|
- if (!has_utmi_pad_registers)
|
|
|
- usb1_reset = of_reset_control_get(phy_np, "utmi-pads");
|
|
|
- else
|
|
|
- usb1_reset = tegra->rst;
|
|
|
-
|
|
|
- if (IS_ERR(usb1_reset)) {
|
|
|
- dev_warn(&pdev->dev,
|
|
|
- "can't get utmi-pads reset from the PHY\n");
|
|
|
- dev_warn(&pdev->dev,
|
|
|
- "continuing, but please update your DT\n");
|
|
|
- } else {
|
|
|
- reset_control_assert(usb1_reset);
|
|
|
- udelay(1);
|
|
|
- reset_control_deassert(usb1_reset);
|
|
|
-
|
|
|
- if (!has_utmi_pad_registers)
|
|
|
- reset_control_put(usb1_reset);
|
|
|
- }
|
|
|
+ /* reset control is shared, hence initialize it first */
|
|
|
+ err = reset_control_deassert(tegra->rst);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
|
|
|
- usb1_reset_attempted = true;
|
|
|
- }
|
|
|
+ err = reset_control_assert(tegra->rst);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
|
|
|
- if (!has_utmi_pad_registers) {
|
|
|
- reset_control_assert(tegra->rst);
|
|
|
- udelay(1);
|
|
|
- reset_control_deassert(tegra->rst);
|
|
|
- }
|
|
|
+ udelay(1);
|
|
|
|
|
|
- of_node_put(phy_np);
|
|
|
+ err = reset_control_deassert(tegra->rst);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -440,7 +426,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
|
|
|
goto cleanup_hcd_create;
|
|
|
}
|
|
|
|
|
|
- tegra->rst = devm_reset_control_get(&pdev->dev, "usb");
|
|
|
+ tegra->rst = devm_reset_control_get_shared(&pdev->dev, "usb");
|
|
|
if (IS_ERR(tegra->rst)) {
|
|
|
dev_err(&pdev->dev, "Can't get ehci reset\n");
|
|
|
err = PTR_ERR(tegra->rst);
|
|
@@ -452,8 +438,10 @@ static int tegra_ehci_probe(struct platform_device *pdev)
|
|
|
goto cleanup_hcd_create;
|
|
|
|
|
|
err = tegra_reset_usb_controller(pdev);
|
|
|
- if (err)
|
|
|
+ if (err) {
|
|
|
+ dev_err(&pdev->dev, "Failed to reset controller\n");
|
|
|
goto cleanup_clk_en;
|
|
|
+ }
|
|
|
|
|
|
u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0);
|
|
|
if (IS_ERR(u_phy)) {
|
|
@@ -538,6 +526,9 @@ static int tegra_ehci_remove(struct platform_device *pdev)
|
|
|
usb_phy_shutdown(hcd->usb_phy);
|
|
|
usb_remove_hcd(hcd);
|
|
|
|
|
|
+ reset_control_assert(tegra->rst);
|
|
|
+ udelay(1);
|
|
|
+
|
|
|
clk_disable_unprepare(tegra->clk);
|
|
|
|
|
|
usb_put_hcd(hcd);
|