From patchwork Thu Sep 4 18:45:38 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Minghuan Lian X-Patchwork-Id: 4843661 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 5954A9F390 for ; Thu, 4 Sep 2014 10:53:18 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id DE378201C0 for ; Thu, 4 Sep 2014 10:53:16 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id AFF44201B9 for ; Thu, 4 Sep 2014 10:53:14 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XPUXq-0004nj-0f; Thu, 04 Sep 2014 10:45:38 +0000 Received: from mail-bn1blp0184.outbound.protection.outlook.com ([207.46.163.184] helo=na01-bn1-obe.outbound.protection.outlook.com) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XPUXn-0004fp-2q for linux-arm-kernel@lists.infradead.org; Thu, 04 Sep 2014 10:45:36 +0000 Received: from DM2PR03MB512.namprd03.prod.outlook.com (10.141.87.22) by DM2PR03MB525.namprd03.prod.outlook.com (10.141.87.139) with Microsoft SMTP Server (TLS) id 15.0.1019.16; Thu, 4 Sep 2014 10:45:12 +0000 Received: from BY2PR03CA056.namprd03.prod.outlook.com (10.141.249.29) by DM2PR03MB512.namprd03.prod.outlook.com (10.141.87.22) with Microsoft SMTP Server (TLS) id 15.0.1019.16; Thu, 4 Sep 2014 10:45:09 +0000 Received: from BL2FFO11FD033.protection.gbl (2a01:111:f400:7c09::140) by BY2PR03CA056.outlook.office365.com (2a01:111:e400:2c5d::29) with Microsoft SMTP Server (TLS) id 15.0.1019.16 via Frontend Transport; Thu, 4 Sep 2014 10:45:08 +0000 Received: from tx30smr01.am.freescale.net (192.88.168.50) by BL2FFO11FD033.mail.protection.outlook.com (10.173.161.129) with Microsoft SMTP Server (TLS) id 15.0.1010.11 via Frontend Transport; Thu, 4 Sep 2014 10:45:08 +0000 Received: from lmh.ap.freescale.net (lmh.ap.freescale.net [10.193.20.14]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id s84Aj1xU027614; Thu, 4 Sep 2014 03:45:05 -0700 From: Minghuan Lian To: Subject: [PATCH 2/2] PCI: Layerscape: Add Layerscape PCIe driver Date: Thu, 4 Sep 2014 18:45:38 +0000 Message-ID: <1409856338-1730-2-git-send-email-Minghuan.Lian@freescale.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1409856338-1730-1-git-send-email-Minghuan.Lian@freescale.com> References: <1409856338-1730-1-git-send-email-Minghuan.Lian@freescale.com> X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:192.88.168.50; CTRY:US; IPV:CAL; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(6009001)(189002)(199003)(86362001)(89996001)(87286001)(104166001)(77156001)(20776003)(229853001)(95666004)(105606002)(80022001)(85852003)(83072002)(64706001)(50466002)(79102001)(76482001)(87936001)(2351001)(47776003)(575784001)(88136002)(107046002)(106466001)(92726001)(50226001)(84676001)(4396001)(48376002)(92566001)(77982001)(81342001)(93916002)(85306004)(97736001)(31966008)(74662001)(74502001)(104016003)(6806004)(44976005)(81542001)(110136001)(62966002)(102836001)(19580405001)(36756003)(26826002)(21056001)(68736004)(46102001)(90102001)(50986999)(99396002)(83322001)(76176999)(19580395003)(2004002); DIR:OUT; SFP:; SCL:1; SRVR:DM2PR03MB512; H:tx30smr01.am.freescale.net; FPR:; MLV:ovrnspm; PTR:InfoDomainNonexistent; MX:1; A:1; LANG:en; MIME-Version: 1.0 X-Microsoft-Antispam: BCL:0;PCL:0;RULEID:;UriScan:;UriScan:; X-Forefront-PRVS: 0324C2C0E2 Received-SPF: Fail (protection.outlook.com: domain of freescale.com does not designate 192.88.168.50 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.168.50; helo=tx30smr01.am.freescale.net; Authentication-Results: spf=fail (sender IP is 192.88.168.50) smtp.mailfrom=Minghuan.Lian@freescale.com; X-Microsoft-Antispam: BCL:0;PCL:0;RULEID:; X-OriginatorOrg: freescale.com X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140904_034535_392270_F4B7E9C8 X-CRM114-Status: GOOD ( 22.49 ) X-Spam-Score: -0.7 (/) Cc: Minghuan Lian , Hu Mingkai-B21284 , Zang Roy-R61911 , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-1.6 required=5.0 tests=BAYES_00, DATE_IN_FUTURE_06_12, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add support for Freescale Layerscape PCIe controller. This driver re-uses the designware core code. Signed-off-by: Minghuan Lian --- .../devicetree/bindings/pci/fsl,ls-pcie.txt | 41 +++ drivers/pci/host/Kconfig | 7 + drivers/pci/host/Makefile | 1 + drivers/pci/host/pci-layerscape.c | 315 +++++++++++++++++++++ include/linux/pci_ids.h | 1 + 5 files changed, 365 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/fsl,ls-pcie.txt create mode 100644 drivers/pci/host/pci-layerscape.c diff --git a/Documentation/devicetree/bindings/pci/fsl,ls-pcie.txt b/Documentation/devicetree/bindings/pci/fsl,ls-pcie.txt new file mode 100644 index 0000000..af2ee1c0 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/fsl,ls-pcie.txt @@ -0,0 +1,41 @@ +Freescale Layerscape PCIe controller + +This PCIe host controller is based on the Synopsis Designware PCIe IP +and thus inherits all the common properties defined in designware-pcie.txt. + +Required properties: +- compatible: should contain "fsl,ls-pcie", to identify the platform, + plus an identifier for specific instance such as "fsl,ls1021a-pcie" +- reg: base addresses and lengths of the PCIe controller +- interrupts: A list of interrupt outputs of the controller. Must contain an + entry for each entry in the interrupt-names property. +- interrupt-names: Must include the following entries: + "intr": The interrupt that is asserted for controller interrupts + "msi": The interrupt that is asserted when an MSI is received + "pme": The interrupt that is asserted when PME state changes + +Example: + + pcie@3400000 { + compatible = "fsl,ls1021a-pcie", "fsl,ls-pcie", "snps,dw-pcie"; + reg = <0x00 0x03400000 0x0 0x00010000 /* controller registers */ + 0x40 0x00000000 0x0 0x00080000>; /* configuration space */ + reg-names = "regs", "config"; + interrupts = , /* controller interrupt */ + , /* MSI interrupt */ + ; /* PME interrupt */ + interrupt-names = "intr", "msi", "pme"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + num-lanes = <4>; + bus-range = <0x0 0xff>; + ranges = <0x81000000 0x0 0x00000000 0x40 0x10000000 0x0 0x00010000 /* downstream I/O */ + 0x82000000 0x0 0x00000000 0x41 0x00000000 0x1 0x00000000>; /* non-prefetchable memory */ + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0000 0 0 1 &gic GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, + <0000 0 0 2 &gic GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>, + <0000 0 0 3 &gic GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>, + <0000 0 0 4 &gic GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>; + }; diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 8922c37..e0d7bbf 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -63,4 +63,11 @@ config PCIE_SPEAR13XX help Say Y here if you want PCIe support on SPEAr13XX SoCs. +config PCI_LAYERSCAPE + bool "Freescale Layerscape PCIe controller" + depends on SOC_LS1021A + select PCIE_DW + help + Say Y here if you want PCIe controller support on Layerscape SoCs. + endmenu diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index d0e88f1..54cd9b2 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o +obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c new file mode 100644 index 0000000..077a20b --- /dev/null +++ b/drivers/pci/host/pci-layerscape.c @@ -0,0 +1,315 @@ +/* + * PCIe host controller driver for Freescale Layerscape SoCs + * + * Copyright (C) 2014 Freescale Semiconductor. + * + * Author: Minghuan Lian + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcie-designware.h" + +/* PEX1/2 Misc Ports Status Register */ +#define PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4) +#define LTSSM_STATE_SHIFT 20 +#define LTSSM_STATE_MASK 0x3f +#define LTSSM_PCIE_L0 0x11 /* L0 state */ + +#define SCFG_SPIMSICR_OFF 0x40 +#define SCFG_SPIMSICR_ADDR 0x1570040 +#define SCFG_SPIMSICLRCR_OFF 0x90 +#define SCFG_SCFGREVCR_OFF 0x200 +#define SCFG_BIT_REVERSE 0xFFFFFFFF +#define SCFG_NO_BIT_REVERSE 0x0 + +#define MSI_LS1021A_DATA(pex_idx) (0xb3 + pex_idx) + +/* Symbol Timer Register and Filter Mask Register 1 */ +#define PCIE_STRFMR1 0x71c + +#define PCIE_LS1021A_BASE 0x3400000 +#define PCIE_LS1021A_REG_SIZE 0x0100000 + +struct ls_pcie { + struct list_head node; + struct device *dev; + struct pci_bus *bus; + void __iomem *dbi; + void __iomem *scfg; + struct pcie_port pp; + int id; + int index; + int irq; + int msi_irq; + int pme_irq; +}; + +static LIST_HEAD(ls_pcie_list); + +#define to_ls_pcie(x) container_of(x, struct ls_pcie, pp) + +static int ls_pcie_link_up(struct pcie_port *pp) +{ + u32 rc, tmp; + struct ls_pcie *pcie = to_ls_pcie(pp); + + tmp = ioread32(pcie->scfg + SCFG_SCFGREVCR_OFF); + iowrite32(SCFG_NO_BIT_REVERSE, pcie->scfg + SCFG_SCFGREVCR_OFF); + + rc = (ioread32(pcie->scfg + PEXMSCPORTSR(pcie->index)) >> + LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; + + iowrite32(tmp, pcie->scfg + SCFG_SCFGREVCR_OFF); + + if (rc < LTSSM_PCIE_L0) + return 0; + + return 1; +} + +static u32 ls_pcie_get_msi_addr(struct pcie_port *pp) +{ + return SCFG_SPIMSICR_ADDR; +} + +static u32 ls_pcie_get_msi_data(struct pcie_port *pp, int pos) +{ + struct ls_pcie *pcie = to_ls_pcie(pp); + + if (pcie->id == PCI_DEVICE_ID_LS1021A) + return MSI_LS1021A_DATA(pcie->index); + + return pos; +} + +static irqreturn_t ls_pcie_msi_irq_handler(int irq, void *data) +{ + struct pcie_port *pp = data; + struct ls_pcie *pcie = to_ls_pcie(pp); + unsigned int msi_irq, processed = 0; + + if (pcie->id == PCI_DEVICE_ID_LS1021A) { + /* clear the interrupt */ + iowrite32(MSI_LS1021A_DATA(pcie->index), + pcie->scfg + SCFG_SPIMSICLRCR_OFF); + + msi_irq = irq_find_mapping(pp->irq_domain, 0); + if (msi_irq) + generic_handle_irq(msi_irq); + else + /* + * that's weird who triggered this? + * just clear it + */ + dev_info(pcie->dev, "unexpected MSI\n"); + + processed++; + } + + return processed > 0 ? IRQ_HANDLED : IRQ_NONE; +} + +static void ls_pcie_msi_clear_irq(struct pcie_port *pp, int irq) +{ +} + +static void ls_pcie_msi_set_irq(struct pcie_port *pp, int irq) +{ + struct ls_pcie *pcie = to_ls_pcie(pp); + + /* MSI needs to set SCFG bit reverse */ + iowrite32(SCFG_BIT_REVERSE, pcie->scfg + SCFG_SCFGREVCR_OFF); +} + +static void ls_pcie_msi_fixup(struct pcie_port *pp) +{ + struct ls_pcie *pcie = to_ls_pcie(pp); + int i; + + if (pcie->id != PCI_DEVICE_ID_LS1021A) + return; + + /** + * LS1021A has only one MSI interrupt + * Set all msi interrupts as used except the first one + */ + for (i = 1; i < MAX_MSI_IRQS; i++) + set_bit(i, pp->msi_irq_in_use); +} + +static void ls_pcie_host_init(struct pcie_port *pp) +{ + struct ls_pcie *pcie = to_ls_pcie(pp); + int count = 0; + u32 val; + + dw_pcie_setup_rc(pp); + + while (!ls_pcie_link_up(pp)) { + usleep_range(100, 1000); + count++; + if (count >= 200) { + dev_err(pp->dev, "phy link never came up\n"); + return; + } + } + + /* Workaround for internal TKT228622 to fix the INTx hang issue */ + val = ioread32(pcie->dbi + PCIE_STRFMR1); + val &= 0xffff; + iowrite32(val, pcie->dbi + PCIE_STRFMR1); + + ls_pcie_msi_fixup(pp); +} + +static struct pcie_host_ops ls_pcie_host_ops = { + .link_up = ls_pcie_link_up, + .host_init = ls_pcie_host_init, + .msi_set_irq = ls_pcie_msi_set_irq, + .msi_clear_irq = ls_pcie_msi_clear_irq, + .get_msi_addr = ls_pcie_get_msi_addr, + .get_msi_data = ls_pcie_get_msi_data, +}; + +static int ls_add_pcie_port(struct ls_pcie *pcie) +{ + struct pcie_port *pp; + int ret; + + if (!pcie) + return -EINVAL; + + pp = &pcie->pp; + pp->dev = pcie->dev; + pp->dbi_base = pcie->dbi; + pp->msi_irq = pcie->msi_irq; + + if (IS_ENABLED(CONFIG_PCI_MSI)) { + ret = devm_request_irq(pp->dev, pp->msi_irq, + ls_pcie_msi_irq_handler, + IRQF_SHARED, "ls-pcie-msi", pp); + if (ret) { + dev_err(pp->dev, "failed to request msi irq\n"); + return ret; + } + } + + pp->root_bus_nr = -1; + pp->ops = &ls_pcie_host_ops; + + ret = dw_pcie_host_init(pp); + if (ret) { + dev_err(pp->dev, "failed to initialize host\n"); + return ret; + } + + return 0; +} + +static int __init ls_pcie_probe(struct platform_device *pdev) +{ + struct ls_pcie *pcie; + struct resource *dbi_base; + struct device_node *np; + int ret; + + pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + pcie->dev = &pdev->dev; + + dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + if (!dbi_base) { + dev_err(&pdev->dev, "missing *regs* space\n"); + return -ENODEV; + } + + pcie->dbi = devm_ioremap_resource(&pdev->dev, dbi_base); + if (IS_ERR(pcie->dbi)) + return PTR_ERR(pcie->dbi); + + if (of_device_is_compatible(pdev->dev.of_node, "fsl,ls1021a-pcie")) { + pcie->id = PCI_DEVICE_ID_LS1021A; + pcie->index = (dbi_base->start - PCIE_LS1021A_BASE) / + PCIE_LS1021A_REG_SIZE; + + /* map SCFG register */ + np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-scfg"); + pcie->scfg = of_iomap(np, 0); + if (!pcie->scfg) { + dev_err(&pdev->dev, "unable to find SCFG registers\n"); + return PTR_ERR(pcie->scfg); + } + } + + /* request interrupt */ + pcie->irq = platform_get_irq_byname(pdev, "intr"); + if (pcie->irq < 0) { + dev_err(&pdev->dev, "failed to get IRQ: %d\n", pcie->irq); + return pcie->irq; + } + + pcie->msi_irq = platform_get_irq_byname(pdev, "msi"); + if (pcie->msi_irq < 0) { + dev_err(&pdev->dev, + "failed to get MSI IRQ: %d\n", pcie->msi_irq); + return pcie->msi_irq; + } + + pcie->pme_irq = platform_get_irq_byname(pdev, "pme"); + if (pcie->pme_irq < 0) { + dev_err(&pdev->dev, + "failed to get PME IRQ: %d\n", pcie->pme_irq); + return pcie->pme_irq; + } + + ret = ls_add_pcie_port(pcie); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, pcie); + list_add(&pcie->node, &ls_pcie_list); + + return 0; +} + +static const struct of_device_id ls_pcie_of_match[] = { + { .compatible = "fsl,ls-pcie" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ls_pcie_of_match); + +static struct platform_driver ls_pcie_driver = { + .driver = { + .name = "layerscape-pcie", + .owner = THIS_MODULE, + .of_match_table = ls_pcie_of_match, + }, +}; + +/* Freescale PCIe driver does not allow module unload */ +static int __init ls_pcie_init(void) +{ + return platform_driver_probe(&ls_pcie_driver, ls_pcie_probe); +} +subsys_initcall(ls_pcie_init); + +MODULE_AUTHOR("Minghuan Lian "); +MODULE_DESCRIPTION("Freescale Layerscape PCIe host controller driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 6ed0bb7..26d4c30 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2442,6 +2442,7 @@ #define PCI_DEVICE_ID_P5020 0x0421 #define PCI_DEVICE_ID_P5010E 0x0428 #define PCI_DEVICE_ID_P5010 0x0429 +#define PCI_DEVICE_ID_LS1021A 0x0e0b #define PCI_DEVICE_ID_MPC8641 0x7010 #define PCI_DEVICE_ID_MPC8641D 0x7011 #define PCI_DEVICE_ID_MPC8610 0x7018