From patchwork Thu May 7 12:33:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prabhakar Mahadev Lad X-Patchwork-Id: 200955 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.7 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 89A61C54E4A for ; Thu, 7 May 2020 12:34:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 620AB21473 for ; Thu, 7 May 2020 12:34:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726635AbgEGMeV (ORCPT ); Thu, 7 May 2020 08:34:21 -0400 Received: from relmlor2.renesas.com ([210.160.252.172]:42478 "EHLO relmlie6.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1725947AbgEGMeU (ORCPT ); Thu, 7 May 2020 08:34:20 -0400 X-IronPort-AV: E=Sophos;i="5.73,363,1583161200"; d="scan'208";a="46285023" Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 07 May 2020 21:34:18 +0900 Received: from localhost.localdomain (unknown [10.226.36.204]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id B2DCD4004D0E; Thu, 7 May 2020 21:34:13 +0900 (JST) From: Lad Prabhakar To: Lorenzo Pieralisi Cc: Rob Herring , Tom Joseph , Jingoo Han , Bjorn Helgaas , Gustavo Pimentel , Marek Vasut , Yoshihiro Shimoda , Shawn Lin , Heiko Stuebner , Kishon Vijay Abraham I , Geert Uytterhoeven , linux-pci@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, Prabhakar , Lad Prabhakar Subject: [PATCH v10 2/8] PCI: rcar: Move shareable code to a common file Date: Thu, 7 May 2020 13:33:13 +0100 Message-Id: <1588854799-13710-3-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1588854799-13710-1-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com> References: <1588854799-13710-1-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Move shareable code to common file pcie-rcar.c and the #defines to pcie-rcar.h so that the common code can be reused with endpoint driver. There are no functional changes with this patch for the host controller driver. Signed-off-by: Lad Prabhakar Reviewed-by: Yoshihiro Shimoda --- drivers/pci/controller/Makefile | 2 +- drivers/pci/controller/pcie-rcar-host.c | 404 +++++++----------------- drivers/pci/controller/pcie-rcar.c | 117 +++++++ drivers/pci/controller/pcie-rcar.h | 131 ++++++++ 4 files changed, 361 insertions(+), 293 deletions(-) create mode 100644 drivers/pci/controller/pcie-rcar.c create mode 100644 drivers/pci/controller/pcie-rcar.h diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile index 9dbccb5b24e1..39802ee32946 100644 --- a/drivers/pci/controller/Makefile +++ b/drivers/pci/controller/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o -obj-$(CONFIG_PCIE_RCAR_HOST) += pcie-rcar-host.o +obj-$(CONFIG_PCIE_RCAR_HOST) += pcie-rcar.o pcie-rcar-host.o obj-$(CONFIG_PCI_HOST_COMMON) += pci-host-common.o obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o diff --git a/drivers/pci/controller/pcie-rcar-host.c b/drivers/pci/controller/pcie-rcar-host.c index 59e55f56e386..d210a36561be 100644 --- a/drivers/pci/controller/pcie-rcar-host.c +++ b/drivers/pci/controller/pcie-rcar-host.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * PCIe driver for Renesas R-Car SoCs - * Copyright (C) 2014 Renesas Electronics Europe Ltd + * Copyright (C) 2014-2020 Renesas Electronics Europe Ltd * * Based on: * arch/sh/drivers/pci/pcie-sh7786.c @@ -30,104 +30,7 @@ #include #include -#define PCIECAR 0x000010 -#define PCIECCTLR 0x000018 -#define CONFIG_SEND_ENABLE BIT(31) -#define TYPE0 (0 << 8) -#define TYPE1 BIT(8) -#define PCIECDR 0x000020 -#define PCIEMSR 0x000028 -#define PCIEINTXR 0x000400 -#define PCIEPHYSR 0x0007f0 -#define PHYRDY BIT(0) -#define PCIEMSITXR 0x000840 - -/* Transfer control */ -#define PCIETCTLR 0x02000 -#define DL_DOWN BIT(3) -#define CFINIT BIT(0) -#define PCIETSTR 0x02004 -#define DATA_LINK_ACTIVE BIT(0) -#define PCIEERRFR 0x02020 -#define UNSUPPORTED_REQUEST BIT(4) -#define PCIEMSIFR 0x02044 -#define PCIEMSIALR 0x02048 -#define MSIFE BIT(0) -#define PCIEMSIAUR 0x0204c -#define PCIEMSIIER 0x02050 - -/* root port address */ -#define PCIEPRAR(x) (0x02080 + ((x) * 0x4)) - -/* local address reg & mask */ -#define PCIELAR(x) (0x02200 + ((x) * 0x20)) -#define PCIELAMR(x) (0x02208 + ((x) * 0x20)) -#define LAM_PREFETCH BIT(3) -#define LAM_64BIT BIT(2) -#define LAR_ENABLE BIT(1) - -/* PCIe address reg & mask */ -#define PCIEPALR(x) (0x03400 + ((x) * 0x20)) -#define PCIEPAUR(x) (0x03404 + ((x) * 0x20)) -#define PCIEPAMR(x) (0x03408 + ((x) * 0x20)) -#define PCIEPTCTLR(x) (0x0340c + ((x) * 0x20)) -#define PAR_ENABLE BIT(31) -#define IO_SPACE BIT(8) - -/* Configuration */ -#define PCICONF(x) (0x010000 + ((x) * 0x4)) -#define PMCAP(x) (0x010040 + ((x) * 0x4)) -#define EXPCAP(x) (0x010070 + ((x) * 0x4)) -#define VCCAP(x) (0x010100 + ((x) * 0x4)) - -/* link layer */ -#define IDSETR1 0x011004 -#define TLCTLR 0x011048 -#define MACSR 0x011054 -#define SPCHGFIN BIT(4) -#define SPCHGFAIL BIT(6) -#define SPCHGSUC BIT(7) -#define LINK_SPEED (0xf << 16) -#define LINK_SPEED_2_5GTS (1 << 16) -#define LINK_SPEED_5_0GTS (2 << 16) -#define MACCTLR 0x011058 -#define MACCTLR_NFTS_MASK GENMASK(23, 16) /* The name is from SH7786 */ -#define SPEED_CHANGE BIT(24) -#define SCRAMBLE_DISABLE BIT(27) -#define LTSMDIS BIT(31) -#define MACCTLR_INIT_VAL (LTSMDIS | MACCTLR_NFTS_MASK) -#define PMSR 0x01105c -#define MACS2R 0x011078 -#define MACCGSPSETR 0x011084 -#define SPCNGRSN BIT(31) - -/* R-Car H1 PHY */ -#define H1_PCIEPHYADRR 0x04000c -#define WRITE_CMD BIT(16) -#define PHY_ACK BIT(24) -#define RATE_POS 12 -#define LANE_POS 8 -#define ADR_POS 0 -#define H1_PCIEPHYDOUTR 0x040014 - -/* R-Car Gen2 PHY */ -#define GEN2_PCIEPHYADDR 0x780 -#define GEN2_PCIEPHYDATA 0x784 -#define GEN2_PCIEPHYCTRL 0x78c - -#define INT_PCI_MSI_NR 32 - -#define RCONF(x) (PCICONF(0) + (x)) -#define RPMCAP(x) (PMCAP(0) + (x)) -#define REXPCAP(x) (EXPCAP(0) + (x)) -#define RVCCAP(x) (VCCAP(0) + (x)) - -#define PCIE_CONF_BUS(b) (((b) & 0xff) << 24) -#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 19) -#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 16) - -#define RCAR_PCI_MAX_RESOURCES 4 -#define MAX_NR_INBOUND_MAPS 6 +#include "pcie-rcar.h" struct rcar_msi { DECLARE_BITMAP(used, INT_PCI_MSI_NR); @@ -145,7 +48,8 @@ static inline struct rcar_msi *to_rcar_msi(struct msi_controller *chip) } /* Structure representing the PCIe interface */ -struct rcar_pcie { +struct rcar_pcie_host { + struct rcar_pcie pcie; struct device *dev; struct phy *phy; void __iomem *base; @@ -153,35 +57,9 @@ struct rcar_pcie { int root_bus_nr; struct clk *bus_clk; struct rcar_msi msi; - int (*phy_init_fn)(struct rcar_pcie *pcie); + int (*phy_init_fn)(struct rcar_pcie_host *host); }; -static void rcar_pci_write_reg(struct rcar_pcie *pcie, u32 val, - unsigned int reg) -{ - writel(val, pcie->base + reg); -} - -static u32 rcar_pci_read_reg(struct rcar_pcie *pcie, unsigned int reg) -{ - return readl(pcie->base + reg); -} - -enum { - RCAR_PCI_ACCESS_READ, - RCAR_PCI_ACCESS_WRITE, -}; - -static void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data) -{ - unsigned int shift = BITS_PER_BYTE * (where & 3); - u32 val = rcar_pci_read_reg(pcie, where & ~3); - - val &= ~(mask << shift); - val |= data << shift; - rcar_pci_write_reg(pcie, val, where & ~3); -} - static u32 rcar_read_conf(struct rcar_pcie *pcie, int where) { unsigned int shift = BITS_PER_BYTE * (where & 3); @@ -191,10 +69,11 @@ static u32 rcar_read_conf(struct rcar_pcie *pcie, int where) } /* Serialization is provided by 'pci_lock' in drivers/pci/access.c */ -static int rcar_pcie_config_access(struct rcar_pcie *pcie, +static int rcar_pcie_config_access(struct rcar_pcie_host *host, unsigned char access_type, struct pci_bus *bus, unsigned int devfn, int where, u32 *data) { + struct rcar_pcie *pcie = &host->pcie; unsigned int dev, func, reg, index; dev = PCI_SLOT(devfn); @@ -226,7 +105,7 @@ static int rcar_pcie_config_access(struct rcar_pcie *pcie, } else { /* Keep an eye out for changes to the root bus number */ if (pci_is_root_bus(bus) && (reg == PCI_PRIMARY_BUS)) - pcie->root_bus_nr = *data & 0xff; + host->root_bus_nr = *data & 0xff; rcar_pci_write_reg(pcie, *data, PCICONF(index)); } @@ -234,7 +113,7 @@ static int rcar_pcie_config_access(struct rcar_pcie *pcie, return PCIBIOS_SUCCESSFUL; } - if (pcie->root_bus_nr < 0) + if (host->root_bus_nr < 0) return PCIBIOS_DEVICE_NOT_FOUND; /* Clear errors */ @@ -245,7 +124,7 @@ static int rcar_pcie_config_access(struct rcar_pcie *pcie, PCIE_CONF_DEV(dev) | PCIE_CONF_FUNC(func) | reg, PCIECAR); /* Enable the configuration access */ - if (bus->parent->number == pcie->root_bus_nr) + if (bus->parent->number == host->root_bus_nr) rcar_pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE0, PCIECCTLR); else rcar_pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE1, PCIECCTLR); @@ -273,10 +152,10 @@ static int rcar_pcie_config_access(struct rcar_pcie *pcie, static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { - struct rcar_pcie *pcie = bus->sysdata; + struct rcar_pcie_host *host = bus->sysdata; int ret; - ret = rcar_pcie_config_access(pcie, RCAR_PCI_ACCESS_READ, + ret = rcar_pcie_config_access(host, RCAR_PCI_ACCESS_READ, bus, devfn, where, val); if (ret != PCIBIOS_SUCCESSFUL) { *val = 0xffffffff; @@ -298,12 +177,12 @@ static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn, static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { - struct rcar_pcie *pcie = bus->sysdata; + struct rcar_pcie_host *host = bus->sysdata; unsigned int shift; u32 data; int ret; - ret = rcar_pcie_config_access(pcie, RCAR_PCI_ACCESS_READ, + ret = rcar_pcie_config_access(host, RCAR_PCI_ACCESS_READ, bus, devfn, where, &data); if (ret != PCIBIOS_SUCCESSFUL) return ret; @@ -322,7 +201,7 @@ static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn, } else data = val; - ret = rcar_pcie_config_access(pcie, RCAR_PCI_ACCESS_WRITE, + ret = rcar_pcie_config_access(host, RCAR_PCI_ACCESS_WRITE, bus, devfn, where, &data); return ret; @@ -333,49 +212,14 @@ static struct pci_ops rcar_pcie_ops = { .write = rcar_pcie_write_conf, }; -static void rcar_pcie_setup_window(int win, struct rcar_pcie *pcie, - struct resource_entry *window) -{ - /* Setup PCIe address space mappings for each resource */ - resource_size_t size; - resource_size_t res_start; - struct resource *res = window->res; - u32 mask; - - rcar_pci_write_reg(pcie, 0x00000000, PCIEPTCTLR(win)); - - /* - * The PAMR mask is calculated in units of 128Bytes, which - * keeps things pretty simple. - */ - size = resource_size(res); - mask = (roundup_pow_of_two(size) / SZ_128) - 1; - rcar_pci_write_reg(pcie, mask << 7, PCIEPAMR(win)); - - if (res->flags & IORESOURCE_IO) - res_start = pci_pio_to_address(res->start) - window->offset; - else - res_start = res->start - window->offset; - - rcar_pci_write_reg(pcie, upper_32_bits(res_start), PCIEPAUR(win)); - rcar_pci_write_reg(pcie, lower_32_bits(res_start) & ~0x7F, - PCIEPALR(win)); - - /* First resource is for IO */ - mask = PAR_ENABLE; - if (res->flags & IORESOURCE_IO) - mask |= IO_SPACE; - - rcar_pci_write_reg(pcie, mask, PCIEPTCTLR(win)); -} - -static int rcar_pcie_setup(struct list_head *resource, struct rcar_pcie *pci) +static int rcar_pcie_setup(struct list_head *resource, + struct rcar_pcie_host *host) { struct resource_entry *win; int i = 0; /* Setup PCI resources */ - resource_list_for_each_entry(win, &pci->resources) { + resource_list_for_each_entry(win, &host->resources) { struct resource *res = win->res; if (!res->flags) @@ -384,11 +228,11 @@ static int rcar_pcie_setup(struct list_head *resource, struct rcar_pcie *pci) switch (resource_type(res)) { case IORESOURCE_IO: case IORESOURCE_MEM: - rcar_pcie_setup_window(i, pci, win); + rcar_pcie_set_outbound(&host->pcie, i, win); i++; break; case IORESOURCE_BUS: - pci->root_bus_nr = res->start; + host->root_bus_nr = res->start; break; default: continue; @@ -454,17 +298,18 @@ static void rcar_pcie_force_speedup(struct rcar_pcie *pcie) (macsr & LINK_SPEED) == LINK_SPEED_5_0GTS ? "5" : "2.5"); } -static void rcar_pcie_hw_enable(struct rcar_pcie *pci) +static void rcar_pcie_hw_enable(struct rcar_pcie_host *host) { + struct rcar_pcie *pcie = &host->pcie; struct resource_entry *win; LIST_HEAD(res); int i = 0; /* Try setting 5 GT/s link speed */ - rcar_pcie_force_speedup(pci); + rcar_pcie_force_speedup(pcie); /* Setup PCI resources */ - resource_list_for_each_entry(win, &pci->resources) { + resource_list_for_each_entry(win, &host->resources) { struct resource *res = win->res; if (!res->flags) @@ -473,35 +318,36 @@ static void rcar_pcie_hw_enable(struct rcar_pcie *pci) switch (resource_type(res)) { case IORESOURCE_IO: case IORESOURCE_MEM: - rcar_pcie_setup_window(i, pci, win); + rcar_pcie_set_outbound(pcie, i, win); i++; break; } } } -static int rcar_pcie_enable(struct rcar_pcie *pcie) +static int rcar_pcie_enable(struct rcar_pcie_host *host) { + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(host); + struct rcar_pcie *pcie = &host->pcie; struct device *dev = pcie->dev; - struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); struct pci_bus *bus, *child; int ret; /* Try setting 5 GT/s link speed */ rcar_pcie_force_speedup(pcie); - rcar_pcie_setup(&bridge->windows, pcie); + rcar_pcie_setup(&bridge->windows, host); pci_add_flags(PCI_REASSIGN_ALL_BUS); bridge->dev.parent = dev; - bridge->sysdata = pcie; - bridge->busnr = pcie->root_bus_nr; + bridge->sysdata = host; + bridge->busnr = host->root_bus_nr; bridge->ops = &rcar_pcie_ops; bridge->map_irq = of_irq_parse_and_map_pci; bridge->swizzle_irq = pci_common_swizzle; if (IS_ENABLED(CONFIG_PCI_MSI)) - bridge->msi = &pcie->msi.chip; + bridge->msi = &host->msi.chip; ret = pci_scan_root_bus_bridge(bridge); if (ret < 0) @@ -563,35 +409,6 @@ static void phy_write_reg(struct rcar_pcie *pcie, phy_wait_for_ack(pcie); } -static int rcar_pcie_wait_for_phyrdy(struct rcar_pcie *pcie) -{ - unsigned int timeout = 10; - - while (timeout--) { - if (rcar_pci_read_reg(pcie, PCIEPHYSR) & PHYRDY) - return 0; - - msleep(5); - } - - return -ETIMEDOUT; -} - -static int rcar_pcie_wait_for_dl(struct rcar_pcie *pcie) -{ - unsigned int timeout = 10000; - - while (timeout--) { - if ((rcar_pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE)) - return 0; - - udelay(5); - cpu_relax(); - } - - return -ETIMEDOUT; -} - static int rcar_pcie_hw_init(struct rcar_pcie *pcie) { int err; @@ -662,8 +479,10 @@ static int rcar_pcie_hw_init(struct rcar_pcie *pcie) return 0; } -static int rcar_pcie_phy_init_h1(struct rcar_pcie *pcie) +static int rcar_pcie_phy_init_h1(struct rcar_pcie_host *host) { + struct rcar_pcie *pcie = &host->pcie; + /* Initialize the phy */ phy_write_reg(pcie, 0, 0x42, 0x1, 0x0EC34191); phy_write_reg(pcie, 1, 0x42, 0x1, 0x0EC34180); @@ -685,8 +504,10 @@ static int rcar_pcie_phy_init_h1(struct rcar_pcie *pcie) return 0; } -static int rcar_pcie_phy_init_gen2(struct rcar_pcie *pcie) +static int rcar_pcie_phy_init_gen2(struct rcar_pcie_host *host) { + struct rcar_pcie *pcie = &host->pcie; + /* * These settings come from the R-Car Series, 2nd Generation User's * Manual, section 50.3.1 (2) Initialization of the physical layer. @@ -705,17 +526,17 @@ static int rcar_pcie_phy_init_gen2(struct rcar_pcie *pcie) return 0; } -static int rcar_pcie_phy_init_gen3(struct rcar_pcie *pcie) +static int rcar_pcie_phy_init_gen3(struct rcar_pcie_host *host) { int err; - err = phy_init(pcie->phy); + err = phy_init(host->phy); if (err) return err; - err = phy_power_on(pcie->phy); + err = phy_power_on(host->phy); if (err) - phy_exit(pcie->phy); + phy_exit(host->phy); return err; } @@ -758,8 +579,9 @@ static void rcar_msi_free(struct rcar_msi *chip, unsigned long irq) static irqreturn_t rcar_pcie_msi_irq(int irq, void *data) { - struct rcar_pcie *pcie = data; - struct rcar_msi *msi = &pcie->msi; + struct rcar_pcie_host *host = data; + struct rcar_pcie *pcie = &host->pcie; + struct rcar_msi *msi = &host->msi; struct device *dev = pcie->dev; unsigned long reg; @@ -798,7 +620,9 @@ static int rcar_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev, struct msi_desc *desc) { struct rcar_msi *msi = to_rcar_msi(chip); - struct rcar_pcie *pcie = container_of(chip, struct rcar_pcie, msi.chip); + struct rcar_pcie_host *host = container_of(chip, struct rcar_pcie_host, + msi.chip); + struct rcar_pcie *pcie = &host->pcie; struct msi_msg msg; unsigned int irq; int hwirq; @@ -827,8 +651,10 @@ static int rcar_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev, static int rcar_msi_setup_irqs(struct msi_controller *chip, struct pci_dev *pdev, int nvec, int type) { - struct rcar_pcie *pcie = container_of(chip, struct rcar_pcie, msi.chip); struct rcar_msi *msi = to_rcar_msi(chip); + struct rcar_pcie_host *host = container_of(chip, struct rcar_pcie_host, + msi.chip); + struct rcar_pcie *pcie = &host->pcie; struct msi_desc *desc; struct msi_msg msg; unsigned int irq; @@ -905,9 +731,9 @@ static const struct irq_domain_ops msi_domain_ops = { .map = rcar_msi_map, }; -static void rcar_pcie_unmap_msi(struct rcar_pcie *pcie) +static void rcar_pcie_unmap_msi(struct rcar_pcie_host *host) { - struct rcar_msi *msi = &pcie->msi; + struct rcar_msi *msi = &host->msi; int i, irq; for (i = 0; i < INT_PCI_MSI_NR; i++) { @@ -919,9 +745,10 @@ static void rcar_pcie_unmap_msi(struct rcar_pcie *pcie) irq_domain_remove(msi->domain); } -static void rcar_pcie_hw_enable_msi(struct rcar_pcie *pcie) +static void rcar_pcie_hw_enable_msi(struct rcar_pcie_host *host) { - struct rcar_msi *msi = &pcie->msi; + struct rcar_pcie *pcie = &host->pcie; + struct rcar_msi *msi = &host->msi; unsigned long base; /* setup MSI data target */ @@ -934,10 +761,11 @@ static void rcar_pcie_hw_enable_msi(struct rcar_pcie *pcie) rcar_pci_write_reg(pcie, 0xffffffff, PCIEMSIIER); } -static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) +static int rcar_pcie_enable_msi(struct rcar_pcie_host *host) { + struct rcar_pcie *pcie = &host->pcie; struct device *dev = pcie->dev; - struct rcar_msi *msi = &pcie->msi; + struct rcar_msi *msi = &host->msi; int err, i; mutex_init(&msi->lock); @@ -960,7 +788,7 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) /* Two irqs are for MSI, but they are also used for non-MSI irqs */ err = devm_request_irq(dev, msi->irq1, rcar_pcie_msi_irq, IRQF_SHARED | IRQF_NO_THREAD, - rcar_msi_irq_chip.name, pcie); + rcar_msi_irq_chip.name, host); if (err < 0) { dev_err(dev, "failed to request IRQ: %d\n", err); goto err; @@ -968,7 +796,7 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) err = devm_request_irq(dev, msi->irq2, rcar_pcie_msi_irq, IRQF_SHARED | IRQF_NO_THREAD, - rcar_msi_irq_chip.name, pcie); + rcar_msi_irq_chip.name, host); if (err < 0) { dev_err(dev, "failed to request IRQ: %d\n", err); goto err; @@ -976,18 +804,19 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) /* setup MSI data target */ msi->pages = __get_free_pages(GFP_KERNEL, 0); - rcar_pcie_hw_enable_msi(pcie); + rcar_pcie_hw_enable_msi(host); return 0; err: - rcar_pcie_unmap_msi(pcie); + rcar_pcie_unmap_msi(host); return err; } -static void rcar_pcie_teardown_msi(struct rcar_pcie *pcie) +static void rcar_pcie_teardown_msi(struct rcar_pcie_host *host) { - struct rcar_msi *msi = &pcie->msi; + struct rcar_pcie *pcie = &host->pcie; + struct rcar_msi *msi = &host->msi; /* Disable all MSI interrupts */ rcar_pci_write_reg(pcie, 0, PCIEMSIIER); @@ -997,18 +826,19 @@ static void rcar_pcie_teardown_msi(struct rcar_pcie *pcie) free_pages(msi->pages, 0); - rcar_pcie_unmap_msi(pcie); + rcar_pcie_unmap_msi(host); } -static int rcar_pcie_get_resources(struct rcar_pcie *pcie) +static int rcar_pcie_get_resources(struct rcar_pcie_host *host) { + struct rcar_pcie *pcie = &host->pcie; struct device *dev = pcie->dev; struct resource res; int err, i; - pcie->phy = devm_phy_optional_get(dev, "pcie"); - if (IS_ERR(pcie->phy)) - return PTR_ERR(pcie->phy); + host->phy = devm_phy_optional_get(dev, "pcie"); + if (IS_ERR(host->phy)) + return PTR_ERR(host->phy); err = of_address_to_resource(dev->of_node, 0, &res); if (err) @@ -1018,10 +848,10 @@ static int rcar_pcie_get_resources(struct rcar_pcie *pcie) if (IS_ERR(pcie->base)) return PTR_ERR(pcie->base); - pcie->bus_clk = devm_clk_get(dev, "pcie_bus"); - if (IS_ERR(pcie->bus_clk)) { + host->bus_clk = devm_clk_get(dev, "pcie_bus"); + if (IS_ERR(host->bus_clk)) { dev_err(dev, "cannot get pcie bus clock\n"); - return PTR_ERR(pcie->bus_clk); + return PTR_ERR(host->bus_clk); } i = irq_of_parse_and_map(dev->of_node, 0); @@ -1030,7 +860,7 @@ static int rcar_pcie_get_resources(struct rcar_pcie *pcie) err = -ENOENT; goto err_irq1; } - pcie->msi.irq1 = i; + host->msi.irq1 = i; i = irq_of_parse_and_map(dev->of_node, 1); if (!i) { @@ -1038,12 +868,12 @@ static int rcar_pcie_get_resources(struct rcar_pcie *pcie) err = -ENOENT; goto err_irq2; } - pcie->msi.irq2 = i; + host->msi.irq2 = i; return 0; err_irq2: - irq_dispose_mapping(pcie->msi.irq1); + irq_dispose_mapping(host->msi.irq1); err_irq1: return err; } @@ -1086,21 +916,8 @@ static int rcar_pcie_inbound_ranges(struct rcar_pcie *pcie, mask = roundup_pow_of_two(size) - 1; mask &= ~0xf; - /* - * Set up 64-bit inbound regions as the range parser doesn't - * distinguish between 32 and 64-bit types. - */ - rcar_pci_write_reg(pcie, lower_32_bits(pci_addr), - PCIEPRAR(idx)); - rcar_pci_write_reg(pcie, lower_32_bits(cpu_addr), PCIELAR(idx)); - rcar_pci_write_reg(pcie, lower_32_bits(mask) | flags, - PCIELAMR(idx)); - - rcar_pci_write_reg(pcie, upper_32_bits(pci_addr), - PCIEPRAR(idx + 1)); - rcar_pci_write_reg(pcie, upper_32_bits(cpu_addr), - PCIELAR(idx + 1)); - rcar_pci_write_reg(pcie, 0, PCIELAMR(idx + 1)); + rcar_pcie_set_inbound(pcie, cpu_addr, pci_addr, + lower_32_bits(mask) | flags, idx, true); pci_addr += size; cpu_addr += size; @@ -1111,14 +928,14 @@ static int rcar_pcie_inbound_ranges(struct rcar_pcie *pcie, return 0; } -static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie *pcie) +static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie_host *host) { - struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(host); struct resource_entry *entry; int index = 0, err = 0; resource_list_for_each_entry(entry, &bridge->dma_ranges) { - err = rcar_pcie_inbound_ranges(pcie, entry, &index); + err = rcar_pcie_inbound_ranges(&host->pcie, entry, &index); if (err) break; } @@ -1145,21 +962,22 @@ static const struct of_device_id rcar_pcie_of_match[] = { static int rcar_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct rcar_pcie_host *host; struct rcar_pcie *pcie; u32 data; int err; struct pci_host_bridge *bridge; - bridge = pci_alloc_host_bridge(sizeof(*pcie)); + bridge = pci_alloc_host_bridge(sizeof(*host)); if (!bridge) return -ENOMEM; - pcie = pci_host_bridge_priv(bridge); - + host = pci_host_bridge_priv(bridge); + pcie = &host->pcie; pcie->dev = dev; - platform_set_drvdata(pdev, pcie); + platform_set_drvdata(pdev, host); - err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, + err = pci_parse_request_of_pci_ranges(dev, &host->resources, &bridge->dma_ranges, NULL); if (err) goto err_free_bridge; @@ -1171,24 +989,24 @@ static int rcar_pcie_probe(struct platform_device *pdev) goto err_pm_disable; } - err = rcar_pcie_get_resources(pcie); + err = rcar_pcie_get_resources(host); if (err < 0) { dev_err(dev, "failed to request resources: %d\n", err); goto err_pm_put; } - err = clk_prepare_enable(pcie->bus_clk); + err = clk_prepare_enable(host->bus_clk); if (err) { dev_err(dev, "failed to enable bus clock: %d\n", err); goto err_unmap_msi_irqs; } - err = rcar_pcie_parse_map_dma_ranges(pcie); + err = rcar_pcie_parse_map_dma_ranges(host); if (err) goto err_clk_disable; - pcie->phy_init_fn = of_device_get_match_data(dev); - err = pcie->phy_init_fn(pcie); + host->phy_init_fn = of_device_get_match_data(dev); + err = host->phy_init_fn(host); if (err) { dev_err(dev, "failed to init PCIe PHY\n"); goto err_clk_disable; @@ -1205,7 +1023,7 @@ static int rcar_pcie_probe(struct platform_device *pdev) dev_info(dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f); if (IS_ENABLED(CONFIG_PCI_MSI)) { - err = rcar_pcie_enable_msi(pcie); + err = rcar_pcie_enable_msi(host); if (err < 0) { dev_err(dev, "failed to enable MSI support: %d\n", @@ -1214,7 +1032,7 @@ static int rcar_pcie_probe(struct platform_device *pdev) } } - err = rcar_pcie_enable(pcie); + err = rcar_pcie_enable(host); if (err) goto err_msi_teardown; @@ -1222,27 +1040,27 @@ static int rcar_pcie_probe(struct platform_device *pdev) err_msi_teardown: if (IS_ENABLED(CONFIG_PCI_MSI)) - rcar_pcie_teardown_msi(pcie); + rcar_pcie_teardown_msi(host); err_phy_shutdown: - if (pcie->phy) { - phy_power_off(pcie->phy); - phy_exit(pcie->phy); + if (host->phy) { + phy_power_off(host->phy); + phy_exit(host->phy); } err_clk_disable: - clk_disable_unprepare(pcie->bus_clk); + clk_disable_unprepare(host->bus_clk); err_unmap_msi_irqs: - irq_dispose_mapping(pcie->msi.irq2); - irq_dispose_mapping(pcie->msi.irq1); + irq_dispose_mapping(host->msi.irq2); + irq_dispose_mapping(host->msi.irq1); err_pm_put: pm_runtime_put(dev); err_pm_disable: pm_runtime_disable(dev); - pci_free_resource_list(&pcie->resources); + pci_free_resource_list(&host->resources); err_free_bridge: pci_free_host_bridge(bridge); @@ -1252,16 +1070,17 @@ static int rcar_pcie_probe(struct platform_device *pdev) static int __maybe_unused rcar_pcie_resume(struct device *dev) { - struct rcar_pcie *pcie = dev_get_drvdata(dev); + struct rcar_pcie_host *host = dev_get_drvdata(dev); + struct rcar_pcie *pcie = &host->pcie; unsigned int data; int err; - err = rcar_pcie_parse_map_dma_ranges(pcie); + err = rcar_pcie_parse_map_dma_ranges(host); if (err) return 0; /* Failure to get a link might just be that no cards are inserted */ - err = pcie->phy_init_fn(pcie); + err = host->phy_init_fn(host); if (err) { dev_info(dev, "PCIe link down\n"); return 0; @@ -1272,16 +1091,17 @@ static int __maybe_unused rcar_pcie_resume(struct device *dev) /* Enable MSI */ if (IS_ENABLED(CONFIG_PCI_MSI)) - rcar_pcie_hw_enable_msi(pcie); + rcar_pcie_hw_enable_msi(host); - rcar_pcie_hw_enable(pcie); + rcar_pcie_hw_enable(host); return 0; } static int rcar_pcie_resume_noirq(struct device *dev) { - struct rcar_pcie *pcie = dev_get_drvdata(dev); + struct rcar_pcie_host *host = dev_get_drvdata(dev); + struct rcar_pcie *pcie = &host->pcie; if (rcar_pci_read_reg(pcie, PMSR) && !(rcar_pci_read_reg(pcie, PCIETCTLR) & DL_DOWN)) diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c new file mode 100644 index 000000000000..cf8840d180c3 --- /dev/null +++ b/drivers/pci/controller/pcie-rcar.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCIe driver for Renesas R-Car SoCs + * Copyright (C) 2014-2020 Renesas Electronics Europe Ltd + * + * Author: Phil Edworthy + */ + +#include +#include + +#include "pcie-rcar.h" + +void rcar_pci_write_reg(struct rcar_pcie *pcie, u32 val, unsigned int reg) +{ + writel(val, pcie->base + reg); +} + +u32 rcar_pci_read_reg(struct rcar_pcie *pcie, unsigned int reg) +{ + return readl(pcie->base + reg); +} + +void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data) +{ + unsigned int shift = BITS_PER_BYTE * (where & 3); + u32 val = rcar_pci_read_reg(pcie, where & ~3); + + val &= ~(mask << shift); + val |= data << shift; + rcar_pci_write_reg(pcie, val, where & ~3); +} + +int rcar_pcie_wait_for_phyrdy(struct rcar_pcie *pcie) +{ + unsigned int timeout = 10; + + while (timeout--) { + if (rcar_pci_read_reg(pcie, PCIEPHYSR) & PHYRDY) + return 0; + + msleep(5); + } + + return -ETIMEDOUT; +} + +int rcar_pcie_wait_for_dl(struct rcar_pcie *pcie) +{ + unsigned int timeout = 10000; + + while (timeout--) { + if ((rcar_pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE)) + return 0; + + udelay(5); + cpu_relax(); + } + + return -ETIMEDOUT; +} + +void rcar_pcie_set_outbound(struct rcar_pcie *pcie, int win, + struct resource_entry *window) +{ + /* Setup PCIe address space mappings for each resource */ + struct resource *res = window->res; + resource_size_t res_start; + resource_size_t size; + u32 mask; + + rcar_pci_write_reg(pcie, 0x00000000, PCIEPTCTLR(win)); + + /* + * The PAMR mask is calculated in units of 128Bytes, which + * keeps things pretty simple. + */ + size = resource_size(res); + mask = (roundup_pow_of_two(size) / SZ_128) - 1; + rcar_pci_write_reg(pcie, mask << 7, PCIEPAMR(win)); + + if (res->flags & IORESOURCE_IO) + res_start = pci_pio_to_address(res->start) - window->offset; + else + res_start = res->start - window->offset; + + rcar_pci_write_reg(pcie, upper_32_bits(res_start), PCIEPAUR(win)); + rcar_pci_write_reg(pcie, lower_32_bits(res_start) & ~0x7F, + PCIEPALR(win)); + + /* First resource is for IO */ + mask = PAR_ENABLE; + if (res->flags & IORESOURCE_IO) + mask |= IO_SPACE; + + rcar_pci_write_reg(pcie, mask, PCIEPTCTLR(win)); +} + +void rcar_pcie_set_inbound(struct rcar_pcie *pcie, u64 cpu_addr, + u64 pci_addr, u64 flags, int idx, bool host) +{ + /* + * Set up 64-bit inbound regions as the range parser doesn't + * distinguish between 32 and 64-bit types. + */ + if (host) + rcar_pci_write_reg(pcie, lower_32_bits(pci_addr), + PCIEPRAR(idx)); + rcar_pci_write_reg(pcie, lower_32_bits(cpu_addr), PCIELAR(idx)); + rcar_pci_write_reg(pcie, flags, PCIELAMR(idx)); + + if (host) + rcar_pci_write_reg(pcie, upper_32_bits(pci_addr), + PCIEPRAR(idx + 1)); + rcar_pci_write_reg(pcie, upper_32_bits(cpu_addr), PCIELAR(idx + 1)); + rcar_pci_write_reg(pcie, 0, PCIELAMR(idx + 1)); +} diff --git a/drivers/pci/controller/pcie-rcar.h b/drivers/pci/controller/pcie-rcar.h new file mode 100644 index 000000000000..97640e16af58 --- /dev/null +++ b/drivers/pci/controller/pcie-rcar.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * PCIe driver for Renesas R-Car SoCs + * Copyright (C) 2014-2020 Renesas Electronics Europe Ltd + * + * Author: Phil Edworthy + */ + +#ifndef _PCIE_RCAR_H +#define _PCIE_RCAR_H + +#define PCIECAR 0x000010 +#define PCIECCTLR 0x000018 +#define CONFIG_SEND_ENABLE BIT(31) +#define TYPE0 (0 << 8) +#define TYPE1 BIT(8) +#define PCIECDR 0x000020 +#define PCIEMSR 0x000028 +#define PCIEINTXR 0x000400 +#define PCIEPHYSR 0x0007f0 +#define PHYRDY BIT(0) +#define PCIEMSITXR 0x000840 + +/* Transfer control */ +#define PCIETCTLR 0x02000 +#define DL_DOWN BIT(3) +#define CFINIT BIT(0) +#define PCIETSTR 0x02004 +#define DATA_LINK_ACTIVE BIT(0) +#define PCIEERRFR 0x02020 +#define UNSUPPORTED_REQUEST BIT(4) +#define PCIEMSIFR 0x02044 +#define PCIEMSIALR 0x02048 +#define MSIFE BIT(0) +#define PCIEMSIAUR 0x0204c +#define PCIEMSIIER 0x02050 + +/* root port address */ +#define PCIEPRAR(x) (0x02080 + ((x) * 0x4)) + +/* local address reg & mask */ +#define PCIELAR(x) (0x02200 + ((x) * 0x20)) +#define PCIELAMR(x) (0x02208 + ((x) * 0x20)) +#define LAM_PREFETCH BIT(3) +#define LAM_64BIT BIT(2) +#define LAR_ENABLE BIT(1) + +/* PCIe address reg & mask */ +#define PCIEPALR(x) (0x03400 + ((x) * 0x20)) +#define PCIEPAUR(x) (0x03404 + ((x) * 0x20)) +#define PCIEPAMR(x) (0x03408 + ((x) * 0x20)) +#define PCIEPTCTLR(x) (0x0340c + ((x) * 0x20)) +#define PAR_ENABLE BIT(31) +#define IO_SPACE BIT(8) + +/* Configuration */ +#define PCICONF(x) (0x010000 + ((x) * 0x4)) +#define PMCAP(x) (0x010040 + ((x) * 0x4)) +#define EXPCAP(x) (0x010070 + ((x) * 0x4)) +#define VCCAP(x) (0x010100 + ((x) * 0x4)) + +/* link layer */ +#define IDSETR1 0x011004 +#define TLCTLR 0x011048 +#define MACSR 0x011054 +#define SPCHGFIN BIT(4) +#define SPCHGFAIL BIT(6) +#define SPCHGSUC BIT(7) +#define LINK_SPEED (0xf << 16) +#define LINK_SPEED_2_5GTS (1 << 16) +#define LINK_SPEED_5_0GTS (2 << 16) +#define MACCTLR 0x011058 +#define MACCTLR_NFTS_MASK GENMASK(23, 16) /* The name is from SH7786 */ +#define SPEED_CHANGE BIT(24) +#define SCRAMBLE_DISABLE BIT(27) +#define LTSMDIS BIT(31) +#define MACCTLR_INIT_VAL (LTSMDIS | MACCTLR_NFTS_MASK) +#define PMSR 0x01105c +#define MACS2R 0x011078 +#define MACCGSPSETR 0x011084 +#define SPCNGRSN BIT(31) + +/* R-Car H1 PHY */ +#define H1_PCIEPHYADRR 0x04000c +#define WRITE_CMD BIT(16) +#define PHY_ACK BIT(24) +#define RATE_POS 12 +#define LANE_POS 8 +#define ADR_POS 0 +#define H1_PCIEPHYDOUTR 0x040014 + +/* R-Car Gen2 PHY */ +#define GEN2_PCIEPHYADDR 0x780 +#define GEN2_PCIEPHYDATA 0x784 +#define GEN2_PCIEPHYCTRL 0x78c + +#define INT_PCI_MSI_NR 32 + +#define RCONF(x) (PCICONF(0) + (x)) +#define RPMCAP(x) (PMCAP(0) + (x)) +#define REXPCAP(x) (EXPCAP(0) + (x)) +#define RVCCAP(x) (VCCAP(0) + (x)) + +#define PCIE_CONF_BUS(b) (((b) & 0xff) << 24) +#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 19) +#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 16) + +#define RCAR_PCI_MAX_RESOURCES 4 +#define MAX_NR_INBOUND_MAPS 6 + +struct rcar_pcie { + struct device *dev; + void __iomem *base; +}; + +enum { + RCAR_PCI_ACCESS_READ, + RCAR_PCI_ACCESS_WRITE, +}; + +void rcar_pci_write_reg(struct rcar_pcie *pcie, u32 val, unsigned int reg); +u32 rcar_pci_read_reg(struct rcar_pcie *pcie, unsigned int reg); +void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data); +int rcar_pcie_wait_for_phyrdy(struct rcar_pcie *pcie); +int rcar_pcie_wait_for_dl(struct rcar_pcie *pcie); +void rcar_pcie_set_outbound(struct rcar_pcie *pcie, int win, + struct resource_entry *window); +void rcar_pcie_set_inbound(struct rcar_pcie *pcie, u64 cpu_addr, + u64 pci_addr, u64 flags, int idx, bool host); + +#endif From patchwork Thu May 7 12:33:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prabhakar Mahadev Lad X-Patchwork-Id: 200954 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.7 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 033B7C38A24 for ; Thu, 7 May 2020 12:35:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D994020663 for ; Thu, 7 May 2020 12:35:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725947AbgEGMfM (ORCPT ); Thu, 7 May 2020 08:35:12 -0400 Received: from relmlor2.renesas.com ([210.160.252.172]:5168 "EHLO relmlie6.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1725939AbgEGMfM (ORCPT ); Thu, 7 May 2020 08:35:12 -0400 X-IronPort-AV: E=Sophos;i="5.73,363,1583161200"; d="scan'208";a="46285059" Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie6.idc.renesas.com with ESMTP; 07 May 2020 21:35:11 +0900 Received: from localhost.localdomain (unknown [10.226.36.204]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id B138A400C089; Thu, 7 May 2020 21:35:06 +0900 (JST) From: Lad Prabhakar To: Lorenzo Pieralisi Cc: Rob Herring , Tom Joseph , Jingoo Han , Bjorn Helgaas , Gustavo Pimentel , Marek Vasut , Yoshihiro Shimoda , Shawn Lin , Heiko Stuebner , Kishon Vijay Abraham I , Geert Uytterhoeven , linux-pci@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, Prabhakar , Lad Prabhakar Subject: [PATCH v10 4/8] PCI: endpoint: Pass page size as argument to pci_epc_mem_init() Date: Thu, 7 May 2020 13:33:15 +0100 Message-Id: <1588854799-13710-5-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1588854799-13710-1-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com> References: <1588854799-13710-1-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org pci_epc_mem_init() internally used page size equal to *PAGE_SIZE* to manage the address space so instead just pass the page size as a argument to pci_epc_mem_init(). Also make pci_epc_mem_init() as a C function instead of a macro function in preparation for adding support for pci-epc-mem core to handle multiple windows. Signed-off-by: Lad Prabhakar Reviewed-by: Yoshihiro Shimoda Acked-by: Kishon Vijay Abraham I --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 2 +- drivers/pci/controller/pcie-rockchip-ep.c | 2 +- drivers/pci/endpoint/pci-epc-mem.c | 7 +++++++ include/linux/pci-epc.h | 5 ++--- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 1c173dad67d1..1c15c8352125 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -450,7 +450,7 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep) epc->max_functions = 1; ret = pci_epc_mem_init(epc, pcie->mem_res->start, - resource_size(pcie->mem_res)); + resource_size(pcie->mem_res), PAGE_SIZE); if (ret < 0) { dev_err(dev, "failed to initialize the memory space\n"); goto err_init; diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index d743b0a48988..5eaf36629a75 100644 --- a/drivers/pci/controller/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c @@ -615,7 +615,7 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev) rockchip_pcie_write(rockchip, BIT(0), PCIE_CORE_PHY_FUNC_CFG); err = pci_epc_mem_init(epc, rockchip->mem_res->start, - resource_size(rockchip->mem_res)); + resource_size(rockchip->mem_res), PAGE_SIZE); if (err < 0) { dev_err(dev, "failed to initialize the memory space\n"); goto err_uninit_port; diff --git a/drivers/pci/endpoint/pci-epc-mem.c b/drivers/pci/endpoint/pci-epc-mem.c index abfac1109a13..cdd1d3821249 100644 --- a/drivers/pci/endpoint/pci-epc-mem.c +++ b/drivers/pci/endpoint/pci-epc-mem.c @@ -93,6 +93,13 @@ return ret; } EXPORT_SYMBOL_GPL(__pci_epc_mem_init); +int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t base, + size_t size, size_t page_size) +{ + return __pci_epc_mem_init(epc, base, size, page_size); +} +EXPORT_SYMBOL_GPL(pci_epc_mem_init); + /** * pci_epc_mem_exit() - cleanup the pci_epc_mem structure * @epc: the EPC device that invoked pci_epc_mem_exit diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h index e0ed9d01f6e5..5bc1de65849e 100644 --- a/include/linux/pci-epc.h +++ b/include/linux/pci-epc.h @@ -137,9 +137,6 @@ struct pci_epc_features { #define devm_pci_epc_create(dev, ops) \ __devm_pci_epc_create((dev), (ops), THIS_MODULE) -#define pci_epc_mem_init(epc, phys_addr, size) \ - __pci_epc_mem_init((epc), (phys_addr), (size), PAGE_SIZE) - static inline void epc_set_drvdata(struct pci_epc *epc, void *data) { dev_set_drvdata(&epc->dev, data); @@ -195,6 +192,8 @@ unsigned int pci_epc_get_first_free_bar(const struct pci_epc_features struct pci_epc *pci_epc_get(const char *epc_name); void pci_epc_put(struct pci_epc *epc); +int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t base, + size_t size, size_t page_size); int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_addr, size_t size, size_t page_size); void pci_epc_mem_exit(struct pci_epc *epc); From patchwork Thu May 7 12:33:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prabhakar Mahadev Lad X-Patchwork-Id: 200953 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id F1BF7C38A24 for ; Thu, 7 May 2020 12:35:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D7C5020663 for ; Thu, 7 May 2020 12:35:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727789AbgEGMfX (ORCPT ); Thu, 7 May 2020 08:35:23 -0400 Received: from relmlor1.renesas.com ([210.160.252.171]:32475 "EHLO relmlie5.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1725939AbgEGMfW (ORCPT ); Thu, 7 May 2020 08:35:22 -0400 X-IronPort-AV: E=Sophos;i="5.73,363,1583161200"; d="scan'208";a="46498190" Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 07 May 2020 21:35:20 +0900 Received: from localhost.localdomain (unknown [10.226.36.204]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 5361F4004D0E; Thu, 7 May 2020 21:35:16 +0900 (JST) From: Lad Prabhakar To: Lorenzo Pieralisi Cc: Rob Herring , Tom Joseph , Jingoo Han , Bjorn Helgaas , Gustavo Pimentel , Marek Vasut , Yoshihiro Shimoda , Shawn Lin , Heiko Stuebner , Kishon Vijay Abraham I , Geert Uytterhoeven , linux-pci@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, Prabhakar , Lad Prabhakar Subject: [PATCH v10 6/8] dt-bindings: PCI: rcar: Add bindings for R-Car PCIe endpoint controller Date: Thu, 7 May 2020 13:33:17 +0100 Message-Id: <1588854799-13710-7-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1588854799-13710-1-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com> References: <1588854799-13710-1-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org This patch adds the bindings for the R-Car PCIe endpoint driver. Signed-off-by: Lad Prabhakar Reviewed-by: Rob Herring Reviewed-by: Yoshihiro Shimoda --- .../devicetree/bindings/pci/rcar-pci-ep.yaml | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml diff --git a/Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml b/Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml new file mode 100644 index 000000000000..aa483c7f27fd --- /dev/null +++ b/Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2020 Renesas Electronics Europe GmbH - https://www.renesas.com/eu/en/ +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/rcar-pci-ep.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas R-Car PCIe Endpoint + +maintainers: + - Lad Prabhakar + - Yoshihiro Shimoda + +properties: + compatible: + items: + - const: renesas,r8a774c0-pcie-ep + - const: renesas,rcar-gen3-pcie-ep + + reg: + maxItems: 5 + + reg-names: + items: + - const: apb-base + - const: memory0 + - const: memory1 + - const: memory2 + - const: memory3 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: pcie + + max-functions: + minimum: 1 + maximum: 1 + +required: + - compatible + - reg + - reg-names + - resets + - power-domains + - clocks + - clock-names + - max-functions + +examples: + - | + #include + #include + + pcie0_ep: pcie-ep@fe000000 { + compatible = "renesas,r8a774c0-pcie-ep", + "renesas,rcar-gen3-pcie-ep"; + reg = <0xfe000000 0x80000>, + <0xfe100000 0x100000>, + <0xfe200000 0x200000>, + <0x30000000 0x8000000>, + <0x38000000 0x8000000>; + reg-names = "apb-base", "memory0", "memory1", "memory2", "memory3"; + resets = <&cpg 319>; + power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>; + clocks = <&cpg CPG_MOD 319>; + clock-names = "pcie"; + max-functions = /bits/ 8 <1>; + }; From patchwork Thu May 7 12:33:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prabhakar Mahadev Lad X-Patchwork-Id: 200952 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.7 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5345BC38A24 for ; Thu, 7 May 2020 12:35:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2FD5C21473 for ; Thu, 7 May 2020 12:35:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727803AbgEGMf1 (ORCPT ); Thu, 7 May 2020 08:35:27 -0400 Received: from relmlor1.renesas.com ([210.160.252.171]:32475 "EHLO relmlie5.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1725939AbgEGMf0 (ORCPT ); Thu, 7 May 2020 08:35:26 -0400 X-IronPort-AV: E=Sophos;i="5.73,363,1583161200"; d="scan'208";a="46498195" Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 07 May 2020 21:35:25 +0900 Received: from localhost.localdomain (unknown [10.226.36.204]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 084B44004D0E; Thu, 7 May 2020 21:35:20 +0900 (JST) From: Lad Prabhakar To: Lorenzo Pieralisi Cc: Rob Herring , Tom Joseph , Jingoo Han , Bjorn Helgaas , Gustavo Pimentel , Marek Vasut , Yoshihiro Shimoda , Shawn Lin , Heiko Stuebner , Kishon Vijay Abraham I , Geert Uytterhoeven , linux-pci@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-renesas-soc@vger.kernel.org, linux-rockchip@lists.infradead.org, linux-arm-kernel@lists.infradead.org, Prabhakar , Lad Prabhakar Subject: [PATCH v10 7/8] PCI: rcar: Add endpoint mode support Date: Thu, 7 May 2020 13:33:18 +0100 Message-Id: <1588854799-13710-8-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1588854799-13710-1-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com> References: <1588854799-13710-1-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add support for R-Car PCIe controller to work in endpoint mode. Signed-off-by: Lad Prabhakar Reviewed-by: Yoshihiro Shimoda --- drivers/pci/controller/Kconfig | 8 + drivers/pci/controller/Makefile | 1 + drivers/pci/controller/pcie-rcar-ep.c | 563 ++++++++++++++++++++++++++ drivers/pci/controller/pcie-rcar.h | 9 + 4 files changed, 581 insertions(+) create mode 100644 drivers/pci/controller/pcie-rcar-ep.c diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index cfdc898450d0..1f9793467f6d 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -71,6 +71,14 @@ config PCIE_RCAR_HOST Say Y here if you want PCIe controller support on R-Car SoCs in host mode. +config PCIE_RCAR_EP + bool "Renesas R-Car PCIe endpoint controller" + depends on ARCH_RENESAS || COMPILE_TEST + depends on PCI_ENDPOINT + help + Say Y here if you want PCIe controller support on R-Car SoCs in + endpoint mode. + config PCI_HOST_COMMON bool select PCI_ECAM diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile index 39802ee32946..741a5204aa5e 100644 --- a/drivers/pci/controller/Makefile +++ b/drivers/pci/controller/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o obj-$(CONFIG_PCIE_RCAR_HOST) += pcie-rcar.o pcie-rcar-host.o +obj-$(CONFIG_PCIE_RCAR_EP) += pcie-rcar.o pcie-rcar-ep.o obj-$(CONFIG_PCI_HOST_COMMON) += pci-host-common.o obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o diff --git a/drivers/pci/controller/pcie-rcar-ep.c b/drivers/pci/controller/pcie-rcar-ep.c new file mode 100644 index 000000000000..b4a288e24aaf --- /dev/null +++ b/drivers/pci/controller/pcie-rcar-ep.c @@ -0,0 +1,563 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCIe endpoint driver for Renesas R-Car SoCs + * Copyright (c) 2020 Renesas Electronics Europe GmbH + * + * Author: Lad Prabhakar + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcie-rcar.h" + +#define RCAR_EPC_MAX_FUNCTIONS 1 + +/* Structure representing the PCIe interface */ +struct rcar_pcie_endpoint { + struct rcar_pcie pcie; + phys_addr_t *ob_mapped_addr; + struct pci_epc_mem_window *ob_window; + u8 max_functions; + unsigned int bar_to_atu[MAX_NR_INBOUND_MAPS]; + unsigned long *ib_window_map; + u32 num_ib_windows; + u32 num_ob_windows; +}; + +static void rcar_pcie_ep_hw_init(struct rcar_pcie *pcie) +{ + u32 val; + + rcar_pci_write_reg(pcie, 0, PCIETCTLR); + + /* Set endpoint mode */ + rcar_pci_write_reg(pcie, 0, PCIEMSR); + + /* Initialize default capabilities. */ + rcar_rmw32(pcie, REXPCAP(0), 0xff, PCI_CAP_ID_EXP); + rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS), + PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ENDPOINT << 4); + rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f, + PCI_HEADER_TYPE_NORMAL); + + /* Write out the physical slot number = 0 */ + rcar_rmw32(pcie, REXPCAP(PCI_EXP_SLTCAP), PCI_EXP_SLTCAP_PSN, 0); + + val = rcar_pci_read_reg(pcie, EXPCAP(1)); + /* device supports fixed 128 bytes MPSS */ + val &= ~GENMASK(2, 0); + rcar_pci_write_reg(pcie, val, EXPCAP(1)); + + val = rcar_pci_read_reg(pcie, EXPCAP(2)); + /* read requests size 128 bytes */ + val &= ~GENMASK(14, 12); + /* payload size 128 bytes */ + val &= ~GENMASK(7, 5); + rcar_pci_write_reg(pcie, val, EXPCAP(2)); + + /* Set target link speed to 5.0 GT/s */ + rcar_rmw32(pcie, EXPCAP(12), PCI_EXP_LNKSTA_CLS, + PCI_EXP_LNKSTA_CLS_5_0GB); + + /* Set the completion timer timeout to the maximum 50ms. */ + rcar_rmw32(pcie, TLCTLR + 1, 0x3f, 50); + + /* Terminate list of capabilities (Next Capability Offset=0) */ + rcar_rmw32(pcie, RVCCAP(0), 0xfff00000, 0); + + /* flush modifications */ + wmb(); +} + +static int rcar_pcie_ep_get_window(struct rcar_pcie_endpoint *ep, + phys_addr_t addr) +{ + int i; + + for (i = 0; i < ep->num_ob_windows; i++) + if (ep->ob_window[i].phys_base == addr) + return i; + + return -EINVAL; +} + +static int rcar_pcie_parse_outbound_ranges(struct rcar_pcie_endpoint *ep, + struct platform_device *pdev) +{ + struct rcar_pcie *pcie = &ep->pcie; + char outbound_name[10]; + struct resource *res; + unsigned int i = 0; + + ep->num_ob_windows = 0; + for (i = 0; i < RCAR_PCI_MAX_RESOURCES; i++) { + sprintf(outbound_name, "memory%u", i); + res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, + outbound_name); + if (!res) { + dev_err(pcie->dev, "missing outbound window %u\n", i); + return -EINVAL; + } + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), + outbound_name)) { + dev_err(pcie->dev, "Cannot request memory region %s.\n", + outbound_name); + return -EIO; + } + + ep->ob_window[i].phys_base = res->start; + ep->ob_window[i].size = resource_size(res); + /* controller doesn't support multiple allocation + * from same window, so set page_size to window size + */ + ep->ob_window[i].page_size = resource_size(res); + } + ep->num_ob_windows = i; + + return 0; +} + +static int rcar_pcie_ep_get_pdata(struct rcar_pcie_endpoint *ep, + struct platform_device *pdev) +{ + struct rcar_pcie *pcie = &ep->pcie; + struct pci_epc_mem_window *window; + struct device *dev = pcie->dev; + struct resource res; + int err; + + err = of_address_to_resource(dev->of_node, 0, &res); + if (err) + return err; + pcie->base = devm_ioremap_resource(dev, &res); + if (IS_ERR(pcie->base)) + return PTR_ERR(pcie->base); + + ep->ob_window = devm_kcalloc(dev, RCAR_PCI_MAX_RESOURCES, + sizeof(*window), GFP_KERNEL); + if (!ep->ob_window) + return -ENOMEM; + + rcar_pcie_parse_outbound_ranges(ep, pdev); + + err = of_property_read_u8(dev->of_node, "max-functions", + &ep->max_functions); + if (err < 0 || ep->max_functions > RCAR_EPC_MAX_FUNCTIONS) + ep->max_functions = RCAR_EPC_MAX_FUNCTIONS; + + return 0; +} + +static int rcar_pcie_ep_write_header(struct pci_epc *epc, u8 fn, + struct pci_epf_header *hdr) +{ + struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); + struct rcar_pcie *pcie = &ep->pcie; + u32 val; + + if (!fn) + val = hdr->vendorid; + else + val = rcar_pci_read_reg(pcie, IDSETR0); + val |= hdr->deviceid << 16; + rcar_pci_write_reg(pcie, val, IDSETR0); + + val = hdr->revid; + val |= hdr->progif_code << 8; + val |= hdr->subclass_code << 16; + val |= hdr->baseclass_code << 24; + rcar_pci_write_reg(pcie, val, IDSETR1); + + if (!fn) + val = hdr->subsys_vendor_id; + else + val = rcar_pci_read_reg(pcie, SUBIDSETR); + val |= hdr->subsys_id << 16; + rcar_pci_write_reg(pcie, val, SUBIDSETR); + + if (hdr->interrupt_pin > PCI_INTERRUPT_INTA) + return -EINVAL; + val = rcar_pci_read_reg(pcie, PCICONF(15)); + val |= (hdr->interrupt_pin << 8); + rcar_pci_write_reg(pcie, val, PCICONF(15)); + + return 0; +} + +static int rcar_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, + struct pci_epf_bar *epf_bar) +{ + int flags = epf_bar->flags | LAR_ENABLE | LAM_64BIT; + struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); + u64 size = 1ULL << fls64(epf_bar->size - 1); + dma_addr_t cpu_addr = epf_bar->phys_addr; + enum pci_barno bar = epf_bar->barno; + struct rcar_pcie *pcie = &ep->pcie; + u32 mask; + int idx; + int err; + + idx = find_first_zero_bit(ep->ib_window_map, ep->num_ib_windows); + if (idx >= ep->num_ib_windows) { + dev_err(pcie->dev, "no free inbound window\n"); + return -EINVAL; + } + + if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) + flags |= IO_SPACE; + + ep->bar_to_atu[bar] = idx; + /* use 64-bit BARs */ + set_bit(idx, ep->ib_window_map); + set_bit(idx + 1, ep->ib_window_map); + + if (cpu_addr > 0) { + unsigned long nr_zeros = __ffs64(cpu_addr); + u64 alignment = 1ULL << nr_zeros; + + size = min(size, alignment); + } + + size = min(size, 1ULL << 32); + + mask = roundup_pow_of_two(size) - 1; + mask &= ~0xf; + + rcar_pcie_set_inbound(pcie, cpu_addr, + 0x0, mask | flags, idx, false); + + err = rcar_pcie_wait_for_phyrdy(pcie); + if (err) { + dev_err(pcie->dev, "phy not ready\n"); + return -EINVAL; + } + + return 0; +} + +static void rcar_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn, + struct pci_epf_bar *epf_bar) +{ + struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); + enum pci_barno bar = epf_bar->barno; + u32 atu_index = ep->bar_to_atu[bar]; + + rcar_pcie_set_inbound(&ep->pcie, 0x0, 0x0, 0x0, bar, false); + + clear_bit(atu_index, ep->ib_window_map); + clear_bit(atu_index + 1, ep->ib_window_map); +} + +static int rcar_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 interrupts) +{ + struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); + struct rcar_pcie *pcie = &ep->pcie; + u32 flags; + + flags = rcar_pci_read_reg(pcie, MSICAP(fn)); + flags |= interrupts << MSICAP0_MMESCAP_OFFSET; + rcar_pci_write_reg(pcie, flags, MSICAP(fn)); + + return 0; +} + +static int rcar_pcie_ep_get_msi(struct pci_epc *epc, u8 fn) +{ + struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); + struct rcar_pcie *pcie = &ep->pcie; + u32 flags; + + flags = rcar_pci_read_reg(pcie, MSICAP(fn)); + if (!(flags & MSICAP0_MSIE)) + return -EINVAL; + + return ((flags & MSICAP0_MMESE_MASK) >> MSICAP0_MMESE_OFFSET); +} + +static int rcar_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, + phys_addr_t addr, u64 pci_addr, size_t size) +{ + struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); + struct rcar_pcie *pcie = &ep->pcie; + struct resource_entry win; + struct resource res; + int window; + int err; + + /* check if we have a link. */ + err = rcar_pcie_wait_for_dl(pcie); + if (err) { + dev_err(pcie->dev, "link not up\n"); + return err; + } + + window = rcar_pcie_ep_get_window(ep, addr); + if (window < 0) { + dev_err(pcie->dev, "failed to get corresponding window\n"); + return -EINVAL; + } + + memset(&win, 0x0, sizeof(win)); + memset(&res, 0x0, sizeof(res)); + res.start = pci_addr; + res.end = pci_addr + size - 1; + res.flags = IORESOURCE_MEM; + win.res = &res; + + rcar_pcie_set_outbound(pcie, window, &win); + + ep->ob_mapped_addr[window] = addr; + + return 0; +} + +static void rcar_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, + phys_addr_t addr) +{ + struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); + struct resource_entry win; + struct resource res; + int idx; + + for (idx = 0; idx < ep->num_ob_windows; idx++) + if (ep->ob_mapped_addr[idx] == addr) + break; + + if (idx >= ep->num_ob_windows) + return; + + memset(&win, 0x0, sizeof(win)); + memset(&res, 0x0, sizeof(res)); + win.res = &res; + rcar_pcie_set_outbound(&ep->pcie, idx, &win); + + ep->ob_mapped_addr[idx] = 0; +} + +static int rcar_pcie_ep_assert_intx(struct rcar_pcie_endpoint *ep, + u8 fn, u8 intx) +{ + struct rcar_pcie *pcie = &ep->pcie; + u32 val; + + val = rcar_pci_read_reg(pcie, PCIEMSITXR); + if ((val & PCI_MSI_FLAGS_ENABLE)) { + dev_err(pcie->dev, "MSI is enabled, cannot assert INTx\n"); + return -EINVAL; + } + + val = rcar_pci_read_reg(pcie, PCICONF(1)); + if ((val & INTDIS)) { + dev_err(pcie->dev, "INTx message transmission is disabled\n"); + return -EINVAL; + } + + val = rcar_pci_read_reg(pcie, PCIEINTXR); + if ((val & ASTINTX)) { + dev_err(pcie->dev, "INTx is already asserted\n"); + return -EINVAL; + } + + val |= ASTINTX; + rcar_pci_write_reg(pcie, val, PCIEINTXR); + usleep_range(1000, 1001); + val = rcar_pci_read_reg(pcie, PCIEINTXR); + val &= ~ASTINTX; + rcar_pci_write_reg(pcie, val, PCIEINTXR); + + return 0; +} + +static int rcar_pcie_ep_assert_msi(struct rcar_pcie *pcie, + u8 fn, u8 interrupt_num) +{ + u16 msi_count; + u32 val; + + /* Check MSI enable bit */ + val = rcar_pci_read_reg(pcie, MSICAP(fn)); + if (!(val & MSICAP0_MSIE)) + return -EINVAL; + + /* Get MSI numbers from MME */ + msi_count = ((val & MSICAP0_MMESE_MASK) >> MSICAP0_MMESE_OFFSET); + msi_count = 1 << msi_count; + + if (!interrupt_num || interrupt_num > msi_count) + return -EINVAL; + + val = rcar_pci_read_reg(pcie, PCIEMSITXR); + rcar_pci_write_reg(pcie, val | (interrupt_num - 1), PCIEMSITXR); + + return 0; +} + +static int rcar_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, + enum pci_epc_irq_type type, + u16 interrupt_num) +{ + struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); + + switch (type) { + case PCI_EPC_IRQ_LEGACY: + return rcar_pcie_ep_assert_intx(ep, fn, 0); + + case PCI_EPC_IRQ_MSI: + return rcar_pcie_ep_assert_msi(&ep->pcie, fn, interrupt_num); + + default: + return -EINVAL; + } +} + +static int rcar_pcie_ep_start(struct pci_epc *epc) +{ + struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); + + rcar_pci_write_reg(&ep->pcie, MACCTLR_INIT_VAL, MACCTLR); + rcar_pci_write_reg(&ep->pcie, CFINIT, PCIETCTLR); + + return 0; +} + +static void rcar_pcie_ep_stop(struct pci_epc *epc) +{ + struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); + + rcar_pci_write_reg(&ep->pcie, 0, PCIETCTLR); +} + +static const struct pci_epc_features rcar_pcie_epc_features = { + .linkup_notifier = false, + .msi_capable = true, + .msix_capable = false, + /* use 64-bit BARs so mark BAR[1,3,5] as reserved */ + .reserved_bar = 1 << BAR_1 | 1 << BAR_3 | 1 << BAR_5, + .bar_fixed_64bit = 1 << BAR_0 | 1 << BAR_2 | 1 << BAR_4, + .bar_fixed_size[0] = 128, + .bar_fixed_size[2] = 256, + .bar_fixed_size[4] = 256, +}; + +static const struct pci_epc_features* +rcar_pcie_ep_get_features(struct pci_epc *epc, u8 func_no) +{ + return &rcar_pcie_epc_features; +} + +static const struct pci_epc_ops rcar_pcie_epc_ops = { + .write_header = rcar_pcie_ep_write_header, + .set_bar = rcar_pcie_ep_set_bar, + .clear_bar = rcar_pcie_ep_clear_bar, + .set_msi = rcar_pcie_ep_set_msi, + .get_msi = rcar_pcie_ep_get_msi, + .map_addr = rcar_pcie_ep_map_addr, + .unmap_addr = rcar_pcie_ep_unmap_addr, + .raise_irq = rcar_pcie_ep_raise_irq, + .start = rcar_pcie_ep_start, + .stop = rcar_pcie_ep_stop, + .get_features = rcar_pcie_ep_get_features, +}; + +static const struct of_device_id rcar_pcie_ep_of_match[] = { + { .compatible = "renesas,r8a774c0-pcie-ep", }, + { .compatible = "renesas,rcar-gen3-pcie-ep" }, + { }, +}; + +static int rcar_pcie_ep_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rcar_pcie_endpoint *ep; + struct rcar_pcie *pcie; + struct pci_epc *epc; + int err; + + ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL); + if (!ep) + return -ENOMEM; + + pcie = &ep->pcie; + pcie->dev = dev; + + pm_runtime_enable(dev); + err = pm_runtime_get_sync(dev); + if (err < 0) { + dev_err(dev, "pm_runtime_get_sync failed\n"); + goto err_pm_disable; + } + + err = rcar_pcie_ep_get_pdata(ep, pdev); + if (err < 0) { + dev_err(dev, "failed to request resources: %d\n", err); + goto err_pm_put; + } + + ep->num_ib_windows = MAX_NR_INBOUND_MAPS; + ep->ib_window_map = + devm_kcalloc(dev, BITS_TO_LONGS(ep->num_ib_windows), + sizeof(long), GFP_KERNEL); + if (!ep->ib_window_map) { + err = -ENOMEM; + dev_err(dev, "failed to allocate memory for inbound map\n"); + goto err_pm_put; + } + + ep->ob_mapped_addr = devm_kcalloc(dev, ep->num_ob_windows, + sizeof(*ep->ob_mapped_addr), + GFP_KERNEL); + if (!ep->ob_mapped_addr) { + err = -ENOMEM; + dev_err(dev, "failed to allocate memory for outbound memory pointers\n"); + goto err_pm_put; + } + + epc = devm_pci_epc_create(dev, &rcar_pcie_epc_ops); + if (IS_ERR(epc)) { + dev_err(dev, "failed to create epc device\n"); + err = PTR_ERR(epc); + goto err_pm_put; + } + + epc->max_functions = ep->max_functions; + epc_set_drvdata(epc, ep); + + rcar_pcie_ep_hw_init(pcie); + + err = pci_epc_multi_mem_init(epc, ep->ob_window, ep->num_ob_windows); + if (err < 0) { + dev_err(dev, "failed to initialize the epc memory space\n"); + goto err_pm_put; + } + + return 0; + +err_pm_put: + pm_runtime_put(dev); + +err_pm_disable: + pm_runtime_disable(dev); + + return err; +} + +static struct platform_driver rcar_pcie_ep_driver = { + .driver = { + .name = "rcar-pcie-ep", + .of_match_table = rcar_pcie_ep_of_match, + .suppress_bind_attrs = true, + }, + .probe = rcar_pcie_ep_probe, +}; +builtin_platform_driver(rcar_pcie_ep_driver); diff --git a/drivers/pci/controller/pcie-rcar.h b/drivers/pci/controller/pcie-rcar.h index 97640e16af58..d4c698b5f821 100644 --- a/drivers/pci/controller/pcie-rcar.h +++ b/drivers/pci/controller/pcie-rcar.h @@ -17,6 +17,7 @@ #define PCIECDR 0x000020 #define PCIEMSR 0x000028 #define PCIEINTXR 0x000400 +#define ASTINTX BIT(16) #define PCIEPHYSR 0x0007f0 #define PHYRDY BIT(0) #define PCIEMSITXR 0x000840 @@ -55,12 +56,20 @@ /* Configuration */ #define PCICONF(x) (0x010000 + ((x) * 0x4)) +#define INTDIS BIT(10) #define PMCAP(x) (0x010040 + ((x) * 0x4)) +#define MSICAP(x) (0x010050 + ((x) * 0x4)) +#define MSICAP0_MSIE BIT(16) +#define MSICAP0_MMESCAP_OFFSET 17 +#define MSICAP0_MMESE_OFFSET 20 +#define MSICAP0_MMESE_MASK GENMASK(22, 20) #define EXPCAP(x) (0x010070 + ((x) * 0x4)) #define VCCAP(x) (0x010100 + ((x) * 0x4)) /* link layer */ +#define IDSETR0 0x011000 #define IDSETR1 0x011004 +#define SUBIDSETR 0x011024 #define TLCTLR 0x011048 #define MACSR 0x011054 #define SPCHGFIN BIT(4)