From patchwork Sun Dec 10 23:07:38 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 846750 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="UEcOLkzA"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yw1wQ3h07z9sR8 for ; Mon, 11 Dec 2017 10:08:22 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752243AbdLJXIN (ORCPT ); Sun, 10 Dec 2017 18:08:13 -0500 Received: from mail-lf0-f68.google.com ([209.85.215.68]:45152 "EHLO mail-lf0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751268AbdLJXH5 (ORCPT ); Sun, 10 Dec 2017 18:07:57 -0500 Received: by mail-lf0-f68.google.com with SMTP id f13so17172481lff.12; Sun, 10 Dec 2017 15:07:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=1wZGWuMktxUif5VN2vaPPhIKEv4XvxKvTEnj0lH4Tew=; b=UEcOLkzA40bbelT01Z71LpxmyYp/0y+yTCbEL8Q2tiQqjPcgbtLijnbosJNI5GdZUZ 9wsZNf2V4eJhXgaeeN6eADBrMfEZ4zn6+AfzW9bE8DGLfvZ1bBc04UqyRjKkYL7Iw3No oDzVDJUWlz1dfaAN0gdYItk4vM8gSQb/LdysBUXjNHiPOIObiATx18NtTey3CR6cxZO3 yBEmVrUo8rZDBdOZj0BY+ZeZK8FcMWGUBrHGzxoBt5dU1rBD8pwPyLbUGJjKWyYB66hF RDx6V/UHaIPa08ui6ioMZyFKLfDMgx+ypVyw5XofMByoQCZC2luKt2yuZzbXhyAU6Xti XT/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=1wZGWuMktxUif5VN2vaPPhIKEv4XvxKvTEnj0lH4Tew=; b=B8tTQ+hyczdWgSdVsNcBA/ptCAlGN+wbHXvEWjx96j4MWZG/UgcyMP6ZqVgx0boxnJ 7YEOBsr+bQiLd290nl+d71Zvrx45XS8pfYhvnB58JB5ibFMLm2u3KYq8rit2e9s0BXQB ogm037O/MtOKoqQvkCvPOiNNjt0RptpDB/uDlRe5OvSUFiWjyNuiatvJhV7DI2aC24Qi 7SwFZkn+Ao/x7uWgoIE7LX4rXLGMxypCSo+Tphb6DqT/VaLHxE/nBqFBu9tgiGMRYNf1 t7rwr6KRR9VNXNxGFGr60nQG+YyIOB+MWN+4QZPzsts8FP9RaFqFc7VM/3Ytu3+EfqfF oOpQ== X-Gm-Message-State: AKGB3mKOXjbHs3OH2Pcf4WJgB9tIYkos9Xem3CL3jnDxG93hkDuCskBA fSKMY8xxCNOrne3W7eJ3U7Y= X-Google-Smtp-Source: AGs4zMZoOpYIoHN0rrP3D5wsuqKjb6rWD85DyVpCMSKcVNbcWbvqbbKwccT9nMjgqQTec5iFXlLRKg== X-Received: by 10.46.88.1 with SMTP id m1mr7675972ljb.72.1512947275903; Sun, 10 Dec 2017 15:07:55 -0800 (PST) Received: from localhost.localdomain (ppp109-252-55-194.pppoe.spdop.ru. [109.252.55.194]) by smtp.gmail.com with ESMTPSA id 75sm2563305lja.84.2017.12.10.15.07.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 10 Dec 2017 15:07:55 -0800 (PST) From: Dmitry Osipenko To: Felipe Balbi , Alan Stern , Greg Kroah-Hartman , Jonathan Hunter , Thierry Reding Cc: linux-usb@vger.kernel.org, linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v1 2/2] usb: tegra: Move UTMI-pads reset from ehci-tegra to tegra-phy Date: Mon, 11 Dec 2017 02:07:38 +0300 Message-Id: <853ce44924e396b907332d4f3ad4ae70eae9bbcc.1512946782.git.digetx@gmail.com> X-Mailer: git-send-email 2.15.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org UTMI pads are shared by USB controllers and reset of UTMI pads is shared with the reset of USB1 controller. Currently reset of UTMI pads is done by the EHCI driver and ChipIdea UDC works because EHCI driver always happen to be probed first. Move reset controls from ehci-tegra to tegra-phy in order to resolve the problem. Signed-off-by: Dmitry Osipenko --- drivers/usb/host/ehci-tegra.c | 87 ++++++++++++++++++--------------------- drivers/usb/phy/phy-tegra-usb.c | 46 +++++++++++++++++++++ include/linux/usb/tegra_usb_phy.h | 2 + 3 files changed, 87 insertions(+), 48 deletions(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index c809f7d2f08f..63294892e198 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -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)) { @@ -537,6 +525,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); diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 019968a5d0ab..d8b43a09228c 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -246,9 +246,48 @@ static int utmip_pad_open(struct tegra_usb_phy *phy) return err; } + phy->pad_rst = devm_reset_control_get_optional_shared( + phy->u_phy.dev, "utmi-pads"); + if (IS_ERR(phy->pad_rst)) { + err = PTR_ERR(phy->pad_rst); + dev_err(phy->u_phy.dev, + "Failed to get UTMI-pads reset: %d\n", err); + return err; + } + + err = reset_control_deassert(phy->pad_rst); + if (err) { + dev_err(phy->u_phy.dev, + "Failed to initialize UTMI-pads reset: %d\n", err); + return err; + } + return 0; } +static int utmip_pad_close(struct tegra_usb_phy *phy) +{ + int ret; + + ret = clk_prepare_enable(phy->pad_clk); + if (ret) { + dev_err(phy->u_phy.dev, + "Failed to enable UTMI-pads clock: %d\n", ret); + return ret; + } + + ret = reset_control_assert(phy->pad_rst); + if (ret) + dev_err(phy->u_phy.dev, + "Failed to assert UTMI-pads reset: %d\n", ret); + + udelay(1); + + clk_disable_unprepare(phy->pad_clk); + + return ret; +} + static void utmip_pad_power_on(struct tegra_usb_phy *phy) { unsigned long val, flags; @@ -260,6 +299,10 @@ static void utmip_pad_power_on(struct tegra_usb_phy *phy) spin_lock_irqsave(&utmip_pad_lock, flags); if (utmip_pad_count++ == 0) { + reset_control_assert(phy->pad_rst); + udelay(1); + reset_control_deassert(phy->pad_rst); + val = readl(base + UTMIP_BIAS_CFG0); val &= ~(UTMIP_OTGPD | UTMIP_BIASPD); @@ -702,6 +745,9 @@ static void tegra_usb_phy_close(struct tegra_usb_phy *phy) if (!IS_ERR(phy->vbus)) regulator_disable(phy->vbus); + if (!phy->is_ulpi_phy) + utmip_pad_close(phy); + clk_disable_unprepare(phy->pll_u); } diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index d641ea1660b7..0c5c3ea8b2d7 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -17,6 +17,7 @@ #define __TEGRA_USB_PHY_H #include +#include #include /* @@ -76,6 +77,7 @@ struct tegra_usb_phy { bool is_legacy_phy; bool is_ulpi_phy; int reset_gpio; + struct reset_control *pad_rst; }; void tegra_usb_phy_preresume(struct usb_phy *phy);