From: Nagarjuna Kristam <nkristam@nvidia.com>
To: <balbi@kernel.org>, <gregkh@linuxfoundation.org>,
<thierry.reding@gmail.com>, <jonathanh@nvidia.com>,
<mark.rutland@arm.com>, <robh+dt@kernel.org>, <kishon@ti.com>
Cc: <devicetree@vger.kernel.org>, <linux-tegra@vger.kernel.org>,
<linux-usb@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
Nagarjuna Kristam <nkristam@nvidia.com>
Subject: [Patch V5 08/21] usb: xhci-tegra: Add OTG support
Date: Mon, 10 Feb 2020 13:41:34 +0530 [thread overview]
Message-ID: <1581322307-11140-9-git-send-email-nkristam@nvidia.com> (raw)
In-Reply-To: <1581322307-11140-1-git-send-email-nkristam@nvidia.com>
Get usb-phy's for availbale USB 2 phys. Register id notifiers for available
usb-phy's to receive role change notifications. Perform PP for the received
role change usb ports.
Signed-off-by: Nagarjuna Kristam <nkristam@nvidia.com>
Acked-by: Thierry Reding <treding@nvidia.com>
---
V5:
- No changes.
---
V4:
- Addressed nit comments from Thierry.
- usb_phy_event is used to detect host mode instead of usb_role.
- Added Acked-by info.
---
V3:
- No changes in this version
---
V2:
- Removed extra line before tegra_xusb_probe API.
---
drivers/usb/host/xhci-tegra.c | 228 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 227 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index 8163aef..32f630b 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -24,6 +24,9 @@
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/phy.h>
+#include <linux/usb/role.h>
#include <soc/tegra/pmc.h>
#include "xhci.h"
@@ -203,6 +206,7 @@ struct tegra_xusb_soc {
bool scale_ss_clock;
bool has_ipfs;
+ bool otg_reset_sspi;
};
struct tegra_xusb_context {
@@ -250,6 +254,14 @@ struct tegra_xusb {
struct phy **phys;
unsigned int num_phys;
+ struct usb_phy **usbphy;
+ unsigned int num_usb_phys;
+ int otg_usb2_port;
+ int otg_usb3_port;
+ bool host_mode;
+ struct notifier_block id_nb;
+ struct work_struct id_work;
+
/* Firmware loading related */
struct {
size_t size;
@@ -1081,6 +1093,205 @@ static int tegra_xusb_enable_firmware_messages(struct tegra_xusb *tegra)
return err;
}
+static void tegra_xhci_set_port_power(struct tegra_xusb *tegra, bool main,
+ bool set)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
+ struct usb_hcd *hcd = main ? xhci->main_hcd : xhci->shared_hcd;
+ unsigned int wait = (!main && !set) ? 1000 : 10;
+ u16 typeReq = set ? SetPortFeature : ClearPortFeature;
+ u16 wIndex = main ? tegra->otg_usb2_port + 1 : tegra->otg_usb3_port + 1;
+ u32 status;
+ u32 stat_power = main ? USB_PORT_STAT_POWER : USB_SS_PORT_STAT_POWER;
+ u32 status_val = set ? stat_power : 0;
+
+ dev_dbg(tegra->dev, "%s():%s %s port power\n", __func__,
+ set ? "set" : "clear", main ? "HS" : "SS");
+
+ hcd->driver->hub_control(hcd, typeReq, USB_PORT_FEAT_POWER, wIndex,
+ NULL, 0);
+
+ do {
+ tegra_xhci_hc_driver.hub_control(hcd, GetPortStatus, 0, wIndex,
+ (char *) &status, sizeof(status));
+ if (status_val == (status & stat_power))
+ break;
+
+ if (!main && !set)
+ usleep_range(600, 700);
+ else
+ usleep_range(10, 20);
+ } while (--wait > 0);
+
+ if (status_val != (status & stat_power))
+ dev_info(tegra->dev, "failed to %s %s PP %d\n",
+ set ? "set" : "clear",
+ main ? "HS" : "SS", status);
+}
+
+static struct phy *tegra_xusb_get_phy(struct tegra_xusb *tegra, char *name,
+ int port)
+{
+ unsigned int i, phy_count = 0;
+
+ for (i = 0; i < tegra->soc->num_types; i++) {
+ if (!strncmp(tegra->soc->phy_types[i].name, "usb2",
+ strlen(name)))
+ return tegra->phys[phy_count+port];
+
+ phy_count += tegra->soc->phy_types[i].num;
+ }
+
+ return NULL;
+}
+
+static void tegra_xhci_id_work(struct work_struct *work)
+{
+ struct tegra_xusb *tegra = container_of(work, struct tegra_xusb,
+ id_work);
+ struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
+ struct tegra_xusb_mbox_msg msg;
+ struct phy *phy = tegra_xusb_get_phy(tegra, "usb2",
+ tegra->otg_usb2_port);
+ u32 status;
+ int ret;
+
+ dev_dbg(tegra->dev, "host mode %s\n", tegra->host_mode ? "on" : "off");
+
+ mutex_lock(&tegra->lock);
+
+ if (tegra->host_mode)
+ phy_set_mode_ext(phy, PHY_MODE_USB_OTG, USB_ROLE_HOST);
+ else
+ phy_set_mode_ext(phy, PHY_MODE_USB_OTG, USB_ROLE_NONE);
+
+ mutex_unlock(&tegra->lock);
+
+ if (tegra->host_mode) {
+ /* switch to host mode */
+ if (tegra->otg_usb3_port >= 0) {
+ if (tegra->soc->otg_reset_sspi) {
+ /* set PP=0 */
+ tegra_xhci_hc_driver.hub_control(
+ xhci->shared_hcd, GetPortStatus,
+ 0, tegra->otg_usb3_port+1,
+ (char *) &status, sizeof(status));
+ if (status & USB_SS_PORT_STAT_POWER)
+ tegra_xhci_set_port_power(tegra, false,
+ false);
+
+ /* reset OTG port SSPI */
+ msg.cmd = MBOX_CMD_RESET_SSPI;
+ msg.data = tegra->otg_usb3_port+1;
+
+ ret = tegra_xusb_mbox_send(tegra, &msg);
+ if (ret < 0) {
+ dev_info(tegra->dev,
+ "failed to RESET_SSPI %d\n",
+ ret);
+ }
+ }
+
+ tegra_xhci_set_port_power(tegra, false, true);
+ }
+
+ tegra_xhci_set_port_power(tegra, true, true);
+
+ } else {
+ if (tegra->otg_usb3_port >= 0)
+ tegra_xhci_set_port_power(tegra, false, false);
+
+ tegra_xhci_set_port_power(tegra, true, false);
+ }
+}
+
+static int tegra_xusb_get_usb2_port(struct tegra_xusb *tegra,
+ struct usb_phy *usbphy)
+{
+ unsigned int i;
+
+ for (i = 0; i < tegra->num_usb_phys; i++) {
+ if (tegra->usbphy[i] && usbphy == tegra->usbphy[i])
+ return i;
+ }
+
+ return -1;
+}
+
+static int tegra_xhci_id_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct tegra_xusb *tegra = container_of(nb, struct tegra_xusb,
+ id_nb);
+ struct usb_phy *usbphy = (struct usb_phy *)data;
+
+ dev_dbg(tegra->dev, "%s(): action is %d", __func__, usbphy->last_event);
+
+ if ((tegra->host_mode && usbphy->last_event == USB_EVENT_ID) ||
+ (!tegra->host_mode && usbphy->last_event != USB_EVENT_ID)) {
+ dev_dbg(tegra->dev, "Same role(%d) received. Ignore",
+ tegra->host_mode);
+ return NOTIFY_OK;
+ }
+
+ tegra->otg_usb2_port = tegra_xusb_get_usb2_port(tegra, usbphy);
+ tegra->otg_usb3_port = tegra_xusb_padctl_get_usb3_companion(
+ tegra->padctl,
+ tegra->otg_usb2_port);
+
+ tegra->host_mode = (usbphy->last_event == USB_EVENT_ID) ? true : false;
+
+ schedule_work(&tegra->id_work);
+
+ return NOTIFY_OK;
+}
+
+static int tegra_xusb_init_usb_phy(struct tegra_xusb *tegra)
+{
+ unsigned int i;
+
+ tegra->usbphy = devm_kcalloc(tegra->dev, tegra->num_usb_phys,
+ sizeof(*tegra->usbphy), GFP_KERNEL);
+ if (!tegra->usbphy)
+ return -ENOMEM;
+
+ INIT_WORK(&tegra->id_work, tegra_xhci_id_work);
+ tegra->id_nb.notifier_call = tegra_xhci_id_notify;
+
+ for (i = 0; i < tegra->num_usb_phys; i++) {
+ struct phy *phy = tegra_xusb_get_phy(tegra, "usb2", i);
+
+ if (!phy)
+ continue;
+
+ tegra->usbphy[i] = devm_usb_get_phy_by_node(tegra->dev,
+ phy->dev.of_node,
+ &tegra->id_nb);
+ if (!IS_ERR(tegra->usbphy[i])) {
+ dev_dbg(tegra->dev, "usbphy-%d registered", i);
+ otg_set_host(tegra->usbphy[i]->otg, &tegra->hcd->self);
+ } else {
+ /*
+ * usb-phy is optional, continue if its not available.
+ */
+ tegra->usbphy[i] = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static void tegra_xusb_deinit_usb_phy(struct tegra_xusb *tegra)
+{
+ unsigned int i;
+
+ cancel_work_sync(&tegra->id_work);
+
+ for (i = 0; i < tegra->num_usb_phys; i++)
+ if (tegra->usbphy[i])
+ otg_set_host(tegra->usbphy[i]->otg, NULL);
+}
+
static int tegra_xusb_probe(struct platform_device *pdev)
{
struct tegra_xusb *tegra;
@@ -1254,8 +1465,11 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto put_powerdomains;
}
- for (i = 0; i < tegra->soc->num_types; i++)
+ for (i = 0; i < tegra->soc->num_types; i++) {
+ if (!strncmp(tegra->soc->phy_types[i].name, "usb2", 4))
+ tegra->num_usb_phys = tegra->soc->phy_types[i].num;
tegra->num_phys += tegra->soc->phy_types[i].num;
+ }
tegra->phys = devm_kcalloc(&pdev->dev, tegra->num_phys,
sizeof(*tegra->phys), GFP_KERNEL);
@@ -1384,6 +1598,12 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto remove_usb3;
}
+ err = tegra_xusb_init_usb_phy(tegra);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to init USB PHY: %d\n", err);
+ goto remove_usb3;
+ }
+
return 0;
remove_usb3:
@@ -1420,6 +1640,8 @@ static int tegra_xusb_remove(struct platform_device *pdev)
struct tegra_xusb *tegra = platform_get_drvdata(pdev);
struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
+ tegra_xusb_deinit_usb_phy(tegra);
+
usb_remove_hcd(xhci->shared_hcd);
usb_put_hcd(xhci->shared_hcd);
xhci->shared_hcd = NULL;
@@ -1694,6 +1916,7 @@ static const struct tegra_xusb_soc tegra124_soc = {
},
.scale_ss_clock = true,
.has_ipfs = true,
+ .otg_reset_sspi = false,
.mbox = {
.cmd = 0xe4,
.data_in = 0xe8,
@@ -1733,6 +1956,7 @@ static const struct tegra_xusb_soc tegra210_soc = {
},
.scale_ss_clock = false,
.has_ipfs = true,
+ .otg_reset_sspi = true,
.mbox = {
.cmd = 0xe4,
.data_in = 0xe8,
@@ -1773,6 +1997,7 @@ static const struct tegra_xusb_soc tegra186_soc = {
},
.scale_ss_clock = false,
.has_ipfs = false,
+ .otg_reset_sspi = false,
.mbox = {
.cmd = 0xe4,
.data_in = 0xe8,
@@ -1802,6 +2027,7 @@ static const struct tegra_xusb_soc tegra194_soc = {
},
.scale_ss_clock = false,
.has_ipfs = false,
+ .otg_reset_sspi = false,
.mbox = {
.cmd = 0x68,
.data_in = 0x6c,
--
2.7.4
next prev parent reply other threads:[~2020-02-10 8:12 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-10 8:11 [Patch V5 00/21] Tegra XUSB OTG support Nagarjuna Kristam
2020-02-10 8:11 ` [Patch V5 01/21] dt-bindings: phy: tegra-xusb: Add usb-role-switch Nagarjuna Kristam
2020-02-10 8:11 ` [Patch V5 02/21] dt-bindings: usb: Add NVIDIA Tegra XUSB device mode controller binding Nagarjuna Kristam
2020-02-10 8:11 ` [Patch V5 03/21] phy: tegra: xusb: Add usb-role-switch support Nagarjuna Kristam
2020-02-17 8:39 ` Thierry Reding
2020-02-10 8:11 ` [Patch V5 04/21] phy: tegra: xusb: Add usb-phy support Nagarjuna Kristam
2020-02-10 8:11 ` [Patch V5 05/21] phy: tegra: xusb: Add support to get companion USB 3 port Nagarjuna Kristam
2020-02-10 8:11 ` [Patch V5 06/21] phy: tegra: xusb: Add set_mode support for USB 2 phy on Tegra210 Nagarjuna Kristam
2020-02-10 8:11 ` [Patch V5 07/21] phy: tegra: xusb: Add set_mode support for UTMI phy on Tegra186 Nagarjuna Kristam
2020-02-10 8:11 ` Nagarjuna Kristam [this message]
2020-02-10 8:11 ` [Patch V5 09/21] usb: gadget: tegra-xudc: Remove usb-role-switch support Nagarjuna Kristam
2020-02-17 8:38 ` Thierry Reding
2020-02-10 8:11 ` [Patch V5 10/21] usb: gadget: tegra-xudc: Add usb-phy support Nagarjuna Kristam
2020-02-17 8:40 ` Thierry Reding
2020-02-10 8:11 ` [Patch V5 11/21] usb: gadget: tegra-xudc: use phy_set_mode to set/unset device mode Nagarjuna Kristam
2020-02-17 8:40 ` Thierry Reding
2020-02-10 8:11 ` [Patch V5 12/21] usb: gadget: tegra-xudc: support multiple device modes Nagarjuna Kristam
2020-02-17 8:42 ` Thierry Reding
2020-02-10 8:11 ` [Patch V5 13/21] arm64: tegra: update OTG port entries for jetson-tx1 Nagarjuna Kristam
2020-02-10 8:11 ` [Patch V5 14/21] arm64: tegra: update OTG port entries for jetson-tx2 Nagarjuna Kristam
2020-02-10 8:11 ` [Patch V5 15/21] arm64: tegra: Add xudc node for Tegra210 Nagarjuna Kristam
2020-02-10 8:11 ` [Patch V5 16/21] arm64: tegra: Enable xudc on Jetson TX1 Nagarjuna Kristam
2020-02-10 8:11 ` [Patch V5 17/21] arm64: tegra: Add xudc node for Tegra186 Nagarjuna Kristam
2020-02-10 8:11 ` [Patch V5 18/21] arm64: tegra: Enable xudc node on Jetson TX2 Nagarjuna Kristam
2020-02-10 8:11 ` [Patch V5 19/21] ARM: tegra: Remove USB 2-0 port from Jetson TK1 padctl Nagarjuna Kristam
2020-02-10 8:11 ` [Patch V5 20/21] arm64: tegra: update OTG port entries for jetson-nano Nagarjuna Kristam
2020-02-10 8:11 ` [Patch V5 21/21] arm64: tegra: Enable xudc node on Jetson nano Nagarjuna Kristam
2020-02-17 8:51 ` [Patch V5 00/21] Tegra XUSB OTG support Thierry Reding
2020-02-27 17:32 ` Thierry Reding
2020-03-04 7:01 ` Greg Kroah-Hartman
2020-03-12 9:22 ` Thierry Reding
2020-03-13 4:48 ` Kishon Vijay Abraham I
2020-03-13 14:48 ` Felipe Balbi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1581322307-11140-9-git-send-email-nkristam@nvidia.com \
--to=nkristam@nvidia.com \
--cc=balbi@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=jonathanh@nvidia.com \
--cc=kishon@ti.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=robh+dt@kernel.org \
--cc=thierry.reding@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).