From patchwork Wed Dec 11 10:30:16 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 299929 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 21C272C00A5 for ; Wed, 11 Dec 2013 21:31:05 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751379Ab3LKKbE (ORCPT ); Wed, 11 Dec 2013 05:31:04 -0500 Received: from mail-out.m-online.net ([212.18.0.10]:43121 "EHLO mail-out.m-online.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751400Ab3LKKbA (ORCPT ); Wed, 11 Dec 2013 05:31:00 -0500 Received: from frontend1.mail.m-online.net (frontend1.mail.intern.m-online.net [192.168.8.180]) by mail-out.m-online.net (Postfix) with ESMTP id 3dfZDH6r3Lz3hj5M; Wed, 11 Dec 2013 11:30:55 +0100 (CET) X-Auth-Info: C2i9bstA5JnerDYlNMFrx1gM43hcuZP3JypF9+J/KNI= Received: from chi.lan (unknown [195.140.253.167]) by smtp-auth.mnet-online.de (Postfix) with ESMTPA id 3dfZDG6h6qzbbgV; Wed, 11 Dec 2013 11:30:54 +0100 (CET) From: Marek Vasut To: linux-pci@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, Marek Vasut , Bjorn Helgaas , Frank Li , Harro Haan , Jingoo Han , Mohit KUMAR , Pratyush Anand , Richard Zhu , Sascha Hauer , Sean Cross , Shawn Guo , Siva Reddy Kallam , Srikanth T Shivanand , Tim Harvey , Troy Kisky , Yinghai Lu Subject: [PATCH V2 5/7] PCI: imx6: Fix link start operation Date: Wed, 11 Dec 2013 11:30:16 +0100 Message-Id: <1386757818-5154-5-git-send-email-marex@denx.de> X-Mailer: git-send-email 1.8.4.2 In-Reply-To: <1386757818-5154-1-git-send-email-marex@denx.de> References: <1386757818-5154-1-git-send-email-marex@denx.de> Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org This patch first forces the link into Gen1 mode before starting up the link and only after the link is up requests the link to start negotiating possible Gen2 mode operation. This is because without such sequence, some PCIe switches are not detected at all. Signed-off-by: Marek Vasut Cc: Bjorn Helgaas Cc: Frank Li Cc: Harro Haan Cc: Jingoo Han Cc: Mohit KUMAR Cc: Pratyush Anand Cc: Richard Zhu Cc: Sascha Hauer Cc: Sean Cross Cc: Shawn Guo Cc: Siva Reddy Kallam Cc: Srikanth T Shivanand Cc: Tim Harvey Cc: Troy Kisky Cc: Yinghai Lu --- drivers/pci/host/pci-imx6.c | 78 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 6 deletions(-) V2: Change the link speed reporting from dev_err() to dev_dbg() so it doesn't polute the kernel output. diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index 4d6f6fe..3028f2c 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -44,6 +44,12 @@ struct imx6_pcie { void __iomem *mem_base; }; +/* PCIe Root Complex registers (memory-mapped) */ +#define PCIE_RC_LCR 0x7c +#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1 +#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2 +#define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK 0xf + /* PCIe Port Logic registers (memory-mapped) */ #define PL_OFFSET 0x700 #define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28) @@ -61,6 +67,9 @@ struct imx6_pcie { #define PCIE_PHY_STAT (PL_OFFSET + 0x110) #define PCIE_PHY_STAT_ACK_LOC 16 +#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C +#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17) + /* PHY registers (not memory-mapped) */ #define PCIE_PHY_RX_ASIC_OUT 0x100D @@ -323,11 +332,71 @@ static int imx6_pcie_wait_for_link(struct pcie_port *pp) return 0; } -static void imx6_pcie_host_init(struct pcie_port *pp) +static int imx6_pcie_start_link(struct pcie_port *pp) { - int count = 0; struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); + uint32_t tmp; + int ret, count; + + /* + * Force Gen1 operation when starting the link. In case the link is + * started in Gen2 mode, there is a possibility the devices on the + * bus will not be detected at all. This happens with PCIe switches. + */ + tmp = readl(pp->dbi_base + PCIE_RC_LCR); + tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; + tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1; + writel(tmp, pp->dbi_base + PCIE_RC_LCR); + + /* Start LTSSM. */ + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); + + ret = imx6_pcie_wait_for_link(pp); + if (ret) + return ret; + + /* Allow Gen2 mode after the link is up. */ + tmp = readl(pp->dbi_base + PCIE_RC_LCR); + tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; + tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2; + writel(tmp, pp->dbi_base + PCIE_RC_LCR); + + /* + * Start Directed Speed Change so the best possible speed both link + * partners support can be negotiated. + */ + tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + tmp |= PORT_LOGIC_SPEED_CHANGE; + writel(tmp, pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + + count = 200; + while (count--) { + tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + /* Test if the speed change finished. */ + if (!(tmp & PORT_LOGIC_SPEED_CHANGE)) + break; + usleep_range(100, 1000); + } + + /* Make sure link training is finished as well! */ + if (count) + ret = imx6_pcie_wait_for_link(pp); + else + ret = -EINVAL; + if (ret) { + dev_err(pp->dev, "Failed to bring link up!\n"); + } else { + tmp = readl(pp->dbi_base + 0x80); + dev_dbg(pp->dev, "Link up, Gen=%i\n", (tmp >> 16) & 0xf); + } + + return ret; +} + +static void imx6_pcie_host_init(struct pcie_port *pp) +{ imx6_pcie_assert_core_reset(pp); imx6_pcie_init_phy(pp); @@ -336,10 +405,7 @@ static void imx6_pcie_host_init(struct pcie_port *pp) dw_pcie_setup_rc(pp); - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); - - imx6_pcie_wait_for_link(pp); + imx6_pcie_start_link(pp); return; }