From patchwork Tue Feb 9 14:51:05 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thierry Reding X-Patchwork-Id: 580872 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 71616140761 for ; Wed, 10 Feb 2016 01:51:14 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=yZDmSpG9; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754316AbcBIOvL (ORCPT ); Tue, 9 Feb 2016 09:51:11 -0500 Received: from mail-wm0-f49.google.com ([74.125.82.49]:36779 "EHLO mail-wm0-f49.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754170AbcBIOvI (ORCPT ); Tue, 9 Feb 2016 09:51:08 -0500 Received: by mail-wm0-f49.google.com with SMTP id p63so161569311wmp.1; Tue, 09 Feb 2016 06:51:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=RYS1L659pbiLQbvaNTz9KfVa6vzFVMom8A19EF+iqGA=; b=yZDmSpG9rzEIVkTCtgtb2sfAJ+xY2YpWrwRW2URIBuGprVNjygTxGcHQE2DUyoFtJt XKD0tJZiu4/wDrAmuaja2XrmsXHN9m4Pg8MyL6q8V+3daJ+Ohh88ZX1tRYY5GbBhqSr/ ngz2gmL46m97B6aXv3pTLopS4dWSt5/297E7rMFBFnVSYmWVKGsOrAV4nTvkZ96vtSk4 jPt7DYEC28+rey4eDkQEGdccINOWVgr6YwSJAsditk/0oFWkW4FBkxH5+eF75vtcidPY I0/i+aYsds9U7rNKLhH1gBQpqNGSpxSdAPjykuYpU4Ccpq/qXhtKITVkqNkMI01npgzF zzRA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=RYS1L659pbiLQbvaNTz9KfVa6vzFVMom8A19EF+iqGA=; b=aILgHt6QL+JoW8QVnHxAwovaemab1tVC+KWHpveWCH30vFD7zBw3jNeXW+4MdpQuLj steyhF3xFBiZ+CL5SWb/BMI28Zp11FS7vU4I2tYd9/FhLC/61RP4+rUeyhl0YsakhAy8 syCoWMIPQGjw9PH9NKs2MAfdkpbZ99Lvnp4ikuHXhaSkuPf7dPwVrP7a3EAYip/eT2Tn 8AvsUM3TzolksbvJV/I00GlD4mMKqukivZAeLB2LpTsAnoc7HiBzEojKRDy6AqZo3+Bt f5pCWfhVyQeI+6n8ByBqZv1xNRslBWQg0hv2ruDv4ba6ggp1FLhTl9mqPDcnD9MvlAS9 bdbA== X-Gm-Message-State: AG10YOSuQArUXjYP4r/bpgZoLj4vYW0FUbn2fGnQhDKuhG+i5currYf5kfLIDq57R2JuBg== X-Received: by 10.194.204.225 with SMTP id lb1mr33076896wjc.156.1455029466809; Tue, 09 Feb 2016 06:51:06 -0800 (PST) Received: from localhost (port-17172.pppoe.wtnet.de. [46.59.128.173]) by smtp.gmail.com with ESMTPSA id et11sm3822561wjc.30.2016.02.09.06.51.05 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 09 Feb 2016 06:51:05 -0800 (PST) From: Thierry Reding To: Bjorn Helgaas Cc: Stephen Warren , Alexandre Courbot , linux-pci@vger.kernel.org, linux-tegra@vger.kernel.org Subject: [PATCH] PCI: tegra: Update for new XUSB pad controller bindings Date: Tue, 9 Feb 2016 15:51:05 +0100 Message-Id: <1455029465-9211-1-git-send-email-thierry.reding@gmail.com> X-Mailer: git-send-email 2.7.1 Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org From: Thierry Reding The current XUSB pad controller bindings are insufficient to describe PHY devices attached to USB controllers. New bindings have been created to overcome these restrictions. As a side-effect each root port now is assigned a set of PHY devices, one for each lane associated with the root port. Signed-off-by: Thierry Reding --- drivers/pci/host/pci-tegra.c | 148 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 132 insertions(+), 16 deletions(-) diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 75c55265ca73..4cb8157a4678 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -307,11 +307,14 @@ struct tegra_pcie { struct tegra_pcie_port { struct tegra_pcie *pcie; + struct device_node *np; struct list_head list; struct resource regs; void __iomem *base; unsigned int index; unsigned int lanes; + + struct phy **phys; }; struct tegra_pcie_bus { @@ -844,6 +847,24 @@ static int tegra_pcie_phy_enable(struct tegra_pcie *pcie) return 0; } +static int tegra_pcie_port_phy_power_on(struct tegra_pcie_port *port) +{ + struct device *dev = port->pcie->dev; + unsigned int i; + int err; + + for (i = 0; i < port->lanes; i++) { + err = phy_power_on(port->phys[i]); + if (err < 0) { + dev_err(dev, "failed to power on PHY#%u: %d\n", i, + err); + return err; + } + } + + return 0; +} + static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) { const struct tegra_pcie_soc_data *soc = pcie->soc_data; @@ -883,14 +904,24 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) afi_writel(pcie, value, AFI_FUSE); } - if (!pcie->phy) - err = tegra_pcie_phy_enable(pcie); - else - err = phy_power_on(pcie->phy); + if (of_get_property(pcie->dev->of_node, "phys", NULL) == NULL) { + list_for_each_entry(port, &pcie->ports, list) { + err = tegra_pcie_port_phy_power_on(port); + if (err < 0) { + dev_err(pcie->dev, + "failed to power on PCIe port: %d\n", + err); + return err; + } + } + } else { + if (!pcie->phy) + err = tegra_pcie_phy_enable(pcie); + else + err = phy_power_on(pcie->phy); - if (err < 0) { - dev_err(pcie->dev, "failed to power on PHY: %d\n", err); - return err; + if (err < 0) + dev_err(pcie->dev, "failed to power on PHY: %d\n", err); } /* take the PCIe interface module out of reset */ @@ -1033,6 +1064,97 @@ static int tegra_pcie_resets_get(struct tegra_pcie *pcie) return 0; } +static int tegra_pcie_phys_get_legacy(struct tegra_pcie *pcie) +{ + int err; + + pcie->phy = devm_phy_optional_get(pcie->dev, "pcie"); + if (IS_ERR(pcie->phy)) { + err = PTR_ERR(pcie->phy); + dev_err(pcie->dev, "failed to get PHY: %d\n", err); + return err; + } + + err = phy_init(pcie->phy); + if (err < 0) { + dev_err(pcie->dev, "failed to initialize PHY: %d\n", err); + return err; + } + + return 0; +} + +static struct phy *devm_of_phy_optional_get_index(struct device *dev, + struct device_node *np, + const char *consumer, + unsigned int index) +{ + struct phy *phy; + char *name; + + name = kasprintf(GFP_KERNEL, "%s-%u", consumer, index); + if (!name) + return ERR_PTR(-ENOMEM); + + phy = devm_of_phy_get(dev, np, name); + kfree(name); + + if (IS_ERR(phy) && PTR_ERR(phy) == -ENODEV) + phy = NULL; + + return phy; +} + +static int tegra_pcie_port_get_phys(struct tegra_pcie_port *port) +{ + struct device *dev = port->pcie->dev; + struct phy *phy; + unsigned int i; + int err; + + port->phys = devm_kcalloc(dev, sizeof(phy), port->lanes, GFP_KERNEL); + if (!port->phys) + return -ENOMEM; + + for (i = 0; i < port->lanes; i++) { + phy = devm_of_phy_optional_get_index(dev, port->np, "pcie", i); + if (IS_ERR(phy)) { + dev_err(dev, "failed to get PHY#%u: %ld\n", i, + PTR_ERR(phy)); + return PTR_ERR(phy); + } + + err = phy_init(phy); + if (err < 0) { + dev_err(dev, "failed to initialize PHY#%u: %d\n", i, + err); + return err; + } + + port->phys[i] = phy; + } + + return 0; +} + +static int tegra_pcie_phys_get(struct tegra_pcie *pcie) +{ + struct tegra_pcie_port *port; + int err; + + if (of_get_property(pcie->dev->of_node, "phys", NULL) != NULL) + return tegra_pcie_phys_get_legacy(pcie); + + list_for_each_entry(port, &pcie->ports, list) { + err = tegra_pcie_port_get_phys(port); + if (err < 0) { + return err; + } + } + + return 0; +} + static int tegra_pcie_get_resources(struct tegra_pcie *pcie) { struct platform_device *pdev = to_platform_device(pcie->dev); @@ -1051,16 +1173,9 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie) return err; } - pcie->phy = devm_phy_optional_get(pcie->dev, "pcie"); - if (IS_ERR(pcie->phy)) { - err = PTR_ERR(pcie->phy); - dev_err(&pdev->dev, "failed to get PHY: %d\n", err); - return err; - } - - err = phy_init(pcie->phy); + err = tegra_pcie_phys_get(pcie); if (err < 0) { - dev_err(&pdev->dev, "failed to initialize PHY: %d\n", err); + dev_err(&pdev->dev, "failed to get PHYs: %d\n", err); return err; } @@ -1725,6 +1840,7 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) rp->index = index; rp->lanes = value; rp->pcie = pcie; + rp->np = port; rp->base = devm_ioremap_resource(pcie->dev, &rp->regs); if (IS_ERR(rp->base))