Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2216465/?format=api
{ "id": 2216465, "url": "http://patchwork.ozlabs.org/api/patches/2216465/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-tegra/patch/20260326135855.2795149-6-thierry.reding@kernel.org/", "project": { "id": 21, "url": "http://patchwork.ozlabs.org/api/projects/21/?format=api", "name": "Linux Tegra Development", "link_name": "linux-tegra", "list_id": "linux-tegra.vger.kernel.org", "list_email": "linux-tegra@vger.kernel.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260326135855.2795149-6-thierry.reding@kernel.org>", "list_archive_url": null, "date": "2026-03-26T13:58:52", "name": "[v3,5/6] PCI: tegra: Add Tegra264 support", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "279dbbe9a91c4d8dfc7034d3b837e55f47de3b97", "submitter": { "id": 92481, "url": "http://patchwork.ozlabs.org/api/people/92481/?format=api", "name": "Thierry Reding", "email": "thierry.reding@kernel.org" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-tegra/patch/20260326135855.2795149-6-thierry.reding@kernel.org/mbox/", "series": [ { "id": 497592, "url": "http://patchwork.ozlabs.org/api/series/497592/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-tegra/list/?series=497592", "date": "2026-03-26T13:58:48", "name": "PCI: tegra: Add Tegra264 support", "version": 3, "mbox": "http://patchwork.ozlabs.org/series/497592/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2216465/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2216465/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "\n <linux-tegra+bounces-13302-incoming=patchwork.ozlabs.org@vger.kernel.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "linux-tegra@vger.kernel.org" ], "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=VbBjIdVO;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c0a:e001:db::12fc:5321; helo=sea.lore.kernel.org;\n envelope-from=linux-tegra+bounces-13302-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)", "smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=\"VbBjIdVO\"", "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=10.30.226.201" ], "Received": [ "from sea.lore.kernel.org (sea.lore.kernel.org\n [IPv6:2600:3c0a:e001:db::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fhQd60FNsz1yGD\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 27 Mar 2026 01:09:30 +1100 (AEDT)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sea.lore.kernel.org (Postfix) with ESMTP id 2D49B30A94ED\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 26 Mar 2026 13:59:13 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id F0F81339714;\n\tThu, 26 Mar 2026 13:59:12 +0000 (UTC)", "from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org\n [10.30.226.201])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id B24542DB78C;\n\tThu, 26 Mar 2026 13:59:12 +0000 (UTC)", "by smtp.kernel.org (Postfix) with ESMTPSA id 13CEFC116C6;\n\tThu, 26 Mar 2026 13:59:11 +0000 (UTC)" ], "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1774533552; cv=none;\n b=gV1FjlCzqaTrkcia2gDkRYDGlz/+r9Ipm6y2ye6QrqhyOqM4uJIisH9Zw9TLhWPequtg8Pjz3cekSWN+yvVEkdxpEy3W43xqC2TRpm80qB+yQQQtCKPQn64f+6A9s8wTZrNXC6x4M4ig+hppzr6E+QlWnm2L952u1uPNQZie9M8=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1774533552; c=relaxed/simple;\n\tbh=ibVgTfS6zzOchUEmfzaHKz0BJo5BzKaMbOgEk4WjVlU=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=rXXLxJv2sMMMPws9Z3uFf/O0Ew16FG+iblrWcNB8aXBMDhC8W3liGXxQ+ijwmRgnWmAj9lFnH+5LzMVxJdD4z6mYDA6Uwm9mfmtBp8QmpV/zDxTgMyEumXdNwEpAJXWEb1chg0i4gb7ia+qU4y3WFWSJvBlKlv74UD3/0aEyFUg=", "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=VbBjIdVO; arc=none smtp.client-ip=10.30.226.201", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;\n\ts=k20201202; t=1774533552;\n\tbh=ibVgTfS6zzOchUEmfzaHKz0BJo5BzKaMbOgEk4WjVlU=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=VbBjIdVOqi+p5nih6Q7sAv3Gq5J2jxxMNQput4HZahvKRC/pVLgjmsBOiFhBUKYXy\n\t KgZ9hbUvHJ5bohwNo6nk+QYTQn69K3A7OtTLV9l9Q3gA5qAnqwu3pqquIFGQHCmGME\n\t 42q6lgRiXPst0n3Ft6Gu/rq9G0mqGWJQKGdlF9bB/09hw4T3VnHbE1dh7AbCSD2oQ5\n\t gzUzRlk6+6+o4SiANTnZ8JeQa1Z/l7stAHKS0K57WDPSwKVHJow7hHRWTJxztv6n7z\n\t IIE3NYOSdnoKqZ6uxseiOw4uPRfdYcCWLkrzS4kpQyUccY+jvpHANuXKYCnZTb8Jip\n\t 4jA+E+W0GnKmw==", "From": "Thierry Reding <thierry.reding@kernel.org>", "To": "Thierry Reding <thierry.reding@kernel.org>,\n Bjorn Helgaas <bhelgaas@google.com>,\n Lorenzo Pieralisi <lpieralisi@kernel.org>, =?utf-8?q?Krzysztof_Wilczy=C5=84?=\n\t=?utf-8?q?ski?= <kwilczynski@kernel.org>,\n Manivannan Sadhasivam <mani@kernel.org>, Rob Herring <robh@kernel.org>,\n Krzysztof Kozlowski <krzk+dt@kernel.org>, Conor Dooley <conor+dt@kernel.org>", "Cc": "Jon Hunter <jonathanh@nvidia.com>,\n\tMikko Perttunen <mperttunen@nvidia.com>,\n\tlinux-pci@vger.kernel.org,\n\tdevicetree@vger.kernel.org,\n\tlinux-tegra@vger.kernel.org", "Subject": "[PATCH v3 5/6] PCI: tegra: Add Tegra264 support", "Date": "Thu, 26 Mar 2026 14:58:52 +0100", "Message-ID": "<20260326135855.2795149-6-thierry.reding@kernel.org>", "X-Mailer": "git-send-email 2.52.0", "In-Reply-To": "<20260326135855.2795149-1-thierry.reding@kernel.org>", "References": "<20260326135855.2795149-1-thierry.reding@kernel.org>", "Precedence": "bulk", "X-Mailing-List": "linux-tegra@vger.kernel.org", "List-Id": "<linux-tegra.vger.kernel.org>", "List-Subscribe": "<mailto:linux-tegra+subscribe@vger.kernel.org>", "List-Unsubscribe": "<mailto:linux-tegra+unsubscribe@vger.kernel.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit" }, "content": "From: Thierry Reding <treding@nvidia.com>\n\nAdd a driver for the PCIe controller found on NVIDIA Tegra264 SoCs. The\ndriver is very small, with its main purpose being to set up the address\ntranslation registers and then creating a standard PCI host using ECAM.\n\nSigned-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>\nSigned-off-by: Thierry Reding <treding@nvidia.com>\n---\nChanges in v3:\n- use separate error messages for BPMP transfer failures vs. BPMP\n command failures\n- use link speed to index into pcie_link_speed to get the correct\n enumeration values for PCIE_SPEED2MBS_ENC\n- pass correct value to icc_set_bw()\n- remove misleading comment\n\nChanges in v2:\n- specify generations applicable for PCI_TEGRA driver to avoid confusion\n- drop SPDX-FileCopyrightText tag\n- rename link_state to link_up to clarify meaning\n- replace memset() by an empty initializer\n- sanity-check only enable BAR regions\n- bring PCI link out of reset in case firmware didn't\n- use common wait times instead of defining our own\n- use core helpers to parse and print PCI link speed\n- fix multi-line comment\n- use dev_err_probe() more ubiquitously\n- fix probe sequence and error cleanup\n- use DEFINE_NOIRQ_DEV_PM_OPS() to avoid warnings for !PM_SUSPEND\n- reuse more standard registers and remove unused register definitions\n- use %pe and ERR_PTR() to print symbolic errors\n- add signed-off-by from Manikanta as the original author\n- add myself as author after significantly modifying the driver\n\n drivers/pci/controller/Kconfig | 10 +-\n drivers/pci/controller/Makefile | 1 +\n drivers/pci/controller/pcie-tegra264.c | 522 +++++++++++++++++++++++++\n 3 files changed, 532 insertions(+), 1 deletion(-)\n create mode 100644 drivers/pci/controller/pcie-tegra264.c", "diff": "diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig\nindex 5aaed8ac6e44..6ead04f7bd6e 100644\n--- a/drivers/pci/controller/Kconfig\n+++ b/drivers/pci/controller/Kconfig\n@@ -254,7 +254,15 @@ config PCI_TEGRA\n \tselect IRQ_MSI_LIB\n \thelp\n \t Say Y here if you want support for the PCIe host controller found\n-\t on NVIDIA Tegra SoCs.\n+\t on NVIDIA Tegra SoCs (Tegra20 through Tegra186).\n+\n+config PCIE_TEGRA264\n+\tbool \"NVIDIA Tegra264 PCIe controller\"\n+\tdepends on ARCH_TEGRA || COMPILE_TEST\n+\tdepends on PCI_MSI\n+\thelp\n+\t Say Y here if you want support for the PCIe host controller found\n+\t on NVIDIA Tegra264 SoCs.\n \n config PCIE_RCAR_HOST\n \tbool \"Renesas R-Car PCIe controller (host mode)\"\ndiff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile\nindex ac8db283f0fe..d478743b5142 100644\n--- a/drivers/pci/controller/Makefile\n+++ b/drivers/pci/controller/Makefile\n@@ -7,6 +7,7 @@ obj-$(CONFIG_PCI_HYPERV_INTERFACE) += pci-hyperv-intf.o\n obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o\n obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o\n obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o\n+obj-$(CONFIG_PCIE_TEGRA264) += pcie-tegra264.o\n obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o\n obj-$(CONFIG_PCIE_RCAR_HOST) += pcie-rcar.o pcie-rcar-host.o\n obj-$(CONFIG_PCIE_RCAR_EP) += pcie-rcar.o pcie-rcar-ep.o\ndiff --git a/drivers/pci/controller/pcie-tegra264.c b/drivers/pci/controller/pcie-tegra264.c\nnew file mode 100644\nindex 000000000000..21872797e41a\n--- /dev/null\n+++ b/drivers/pci/controller/pcie-tegra264.c\n@@ -0,0 +1,522 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/*\n+ * PCIe host controller driver for Tegra264 SoC\n+ *\n+ * Copyright (c) 2022-2026, NVIDIA CORPORATION. All rights reserved.\n+ */\n+\n+#include <linux/delay.h>\n+#include <linux/gpio/consumer.h>\n+#include <linux/init.h>\n+#include <linux/interconnect.h>\n+#include <linux/interrupt.h>\n+#include <linux/iopoll.h>\n+#include <linux/kernel.h>\n+#include <linux/module.h>\n+#include <linux/of_address.h>\n+#include <linux/of_device.h>\n+#include <linux/of.h>\n+#include <linux/of_pci.h>\n+#include <linux/of_platform.h>\n+#include <linux/pci-ecam.h>\n+#include <linux/pci.h>\n+#include <linux/pinctrl/consumer.h>\n+#include <linux/platform_device.h>\n+#include <linux/pm_runtime.h>\n+\n+#include <soc/tegra/bpmp.h>\n+#include <soc/tegra/bpmp-abi.h>\n+#include <soc/tegra/fuse.h>\n+\n+#include \"../pci.h\"\n+\n+/* XAL registers */\n+#define XAL_RC_ECAM_BASE_HI\t\t\t0x00\n+#define XAL_RC_ECAM_BASE_LO\t\t\t0x04\n+#define XAL_RC_ECAM_BUSMASK\t\t\t0x08\n+#define XAL_RC_IO_BASE_HI\t\t\t0x0c\n+#define XAL_RC_IO_BASE_LO\t\t\t0x10\n+#define XAL_RC_IO_LIMIT_HI\t\t\t0x14\n+#define XAL_RC_IO_LIMIT_LO\t\t\t0x18\n+#define XAL_RC_MEM_32BIT_BASE_HI\t\t0x1c\n+#define XAL_RC_MEM_32BIT_BASE_LO\t\t0x20\n+#define XAL_RC_MEM_32BIT_LIMIT_HI\t\t0x24\n+#define XAL_RC_MEM_32BIT_LIMIT_LO\t\t0x28\n+#define XAL_RC_MEM_64BIT_BASE_HI\t\t0x2c\n+#define XAL_RC_MEM_64BIT_BASE_LO\t\t0x30\n+#define XAL_RC_MEM_64BIT_LIMIT_HI\t\t0x34\n+#define XAL_RC_MEM_64BIT_LIMIT_LO\t\t0x38\n+#define XAL_RC_BAR_CNTL_STANDARD\t\t0x40\n+#define XAL_RC_BAR_CNTL_STANDARD_IOBAR_EN\tBIT(0)\n+#define XAL_RC_BAR_CNTL_STANDARD_32B_BAR_EN\tBIT(1)\n+#define XAL_RC_BAR_CNTL_STANDARD_64B_BAR_EN\tBIT(2)\n+\n+/* XTL registers */\n+#define XTL_RC_PCIE_CFG_LINK_STATUS\t\t0x5a\n+\n+#define XTL_RC_MGMT_PERST_CONTROL\t\t0x218\n+#define XTL_RC_MGMT_PERST_CONTROL_PERST_O_N\tBIT(0)\n+\n+#define XTL_RC_MGMT_CLOCK_CONTROL\t\t0x47c\n+#define XTL_RC_MGMT_CLOCK_CONTROL_PEX_CLKREQ_I_N_PIN_USE_CONV_TO_PRSNT\tBIT(9)\n+\n+struct tegra264_pcie {\n+\tstruct device *dev;\n+\tbool link_up;\n+\n+\t/* I/O memory */\n+\tvoid __iomem *xal;\n+\tvoid __iomem *xtl;\n+\tvoid __iomem *ecam;\n+\n+\t/* bridge configuration */\n+\tstruct pci_config_window *cfg;\n+\tstruct pci_host_bridge *bridge;\n+\n+\t/* wake IRQ */\n+\tstruct gpio_desc *wake_gpio;\n+\tunsigned int wake_irq;\n+\n+\t/* BPMP and bandwidth management */\n+\tstruct icc_path *icc_path;\n+\tstruct tegra_bpmp *bpmp;\n+\tu32 ctl_id;\n+};\n+\n+static int tegra264_pcie_parse_dt(struct tegra264_pcie *pcie)\n+{\n+\tint err;\n+\n+\tpcie->wake_gpio = devm_gpiod_get_optional(pcie->dev, \"nvidia,pex-wake\",\n+\t\t\t\t\t\t GPIOD_IN);\n+\tif (IS_ERR(pcie->wake_gpio))\n+\t\treturn PTR_ERR(pcie->wake_gpio);\n+\n+\tif (pcie->wake_gpio) {\n+\t\tdevice_init_wakeup(pcie->dev, true);\n+\n+\t\terr = gpiod_to_irq(pcie->wake_gpio);\n+\t\tif (err < 0) {\n+\t\t\tdev_err(pcie->dev, \"failed to get wake IRQ: %pe\\n\",\n+\t\t\t\tERR_PTR(err));\n+\t\t\treturn err;\n+\t\t}\n+\n+\t\tpcie->wake_irq = (unsigned int)err;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void tegra264_pcie_bpmp_set_rp_state(struct tegra264_pcie *pcie)\n+{\n+\tstruct tegra_bpmp_message msg = {};\n+\tstruct mrq_pcie_request req = {};\n+\tint err;\n+\n+\treq.cmd = CMD_PCIE_RP_CONTROLLER_OFF;\n+\treq.rp_ctrlr_off.rp_controller = pcie->ctl_id;\n+\n+\tmsg.mrq = MRQ_PCIE;\n+\tmsg.tx.data = &req;\n+\tmsg.tx.size = sizeof(req);\n+\n+\terr = tegra_bpmp_transfer(pcie->bpmp, &msg);\n+\tif (err)\n+\t\tdev_info(pcie->dev, \"BPMP transfer failed for PCIe #%u: %pe\\n\",\n+\t\t\t pcie->ctl_id, ERR_PTR(err));\n+\n+\tif (msg.rx.ret)\n+\t\tdev_info(pcie->dev, \"failed to turn off PCIe #%u: %d\\n\",\n+\t\t\t pcie->ctl_id, msg.rx.ret);\n+}\n+\n+static void tegra264_pcie_icc_set(struct tegra264_pcie *pcie)\n+{\n+\tu32 value, speed, width, bw;\n+\tint err;\n+\n+\tvalue = readw(pcie->ecam + XTL_RC_PCIE_CFG_LINK_STATUS);\n+\tspeed = FIELD_GET(PCI_EXP_LNKSTA_CLS, value);\n+\twidth = FIELD_GET(PCI_EXP_LNKSTA_NLW, value);\n+\n+\tbw = width * (PCIE_SPEED2MBS_ENC(pcie_link_speed[speed]));\n+\tvalue = MBps_to_icc(bw / BITS_PER_BYTE);\n+\n+\terr = icc_set_bw(pcie->icc_path, value, value);\n+\tif (err < 0)\n+\t\tdev_err(pcie->dev,\n+\t\t\t\"failed to request bandwidth (%u Mbps): %pe\\n\",\n+\t\t\tbw, ERR_PTR(err));\n+}\n+\n+/*\n+ * The various memory regions used by the controller (I/O, memory, ECAM) are\n+ * set up during early boot and have hardware-level protections in place. If\n+ * the DT ranges don't match what's been setup, the controller won't be able\n+ * to write the address endpoints properly, so make sure to validate that DT\n+ * and firmware programming agree on these ranges.\n+ */\n+static bool tegra264_pcie_check_ranges(struct platform_device *pdev)\n+{\n+\tstruct tegra264_pcie *pcie = platform_get_drvdata(pdev);\n+\tstruct device_node *np = pcie->dev->of_node;\n+\tstruct of_pci_range_parser parser;\n+\tphys_addr_t phys, limit, hi, lo;\n+\tstruct of_pci_range range;\n+\tstruct resource *res;\n+\tbool status = true;\n+\tu32 value;\n+\tint err;\n+\n+\terr = of_pci_range_parser_init(&parser, np);\n+\tif (err < 0)\n+\t\treturn false;\n+\n+\tfor_each_of_pci_range(&parser, &range) {\n+\t\tunsigned int addr_hi, addr_lo, limit_hi, limit_lo, enable;\n+\t\tunsigned long type = range.flags & IORESOURCE_TYPE_BITS;\n+\t\tphys_addr_t start, end, mask;\n+\t\tconst char *region = NULL;\n+\n+\t\tend = range.cpu_addr + range.size - 1;\n+\t\tstart = range.cpu_addr;\n+\n+\t\tswitch (type) {\n+\t\tcase IORESOURCE_IO:\n+\t\t\taddr_hi = XAL_RC_IO_BASE_HI;\n+\t\t\taddr_lo = XAL_RC_IO_BASE_LO;\n+\t\t\tlimit_hi = XAL_RC_IO_LIMIT_HI;\n+\t\t\tlimit_lo = XAL_RC_IO_LIMIT_LO;\n+\t\t\tenable = XAL_RC_BAR_CNTL_STANDARD_IOBAR_EN;\n+\t\t\tmask = SZ_64K - 1;\n+\t\t\tregion = \"I/O\";\n+\t\t\tbreak;\n+\n+\t\tcase IORESOURCE_MEM:\n+\t\t\tif (range.flags & IORESOURCE_PREFETCH) {\n+\t\t\t\taddr_hi = XAL_RC_MEM_64BIT_BASE_HI;\n+\t\t\t\taddr_lo = XAL_RC_MEM_64BIT_BASE_LO;\n+\t\t\t\tlimit_hi = XAL_RC_MEM_64BIT_LIMIT_HI;\n+\t\t\t\tlimit_lo = XAL_RC_MEM_64BIT_LIMIT_LO;\n+\t\t\t\tenable = XAL_RC_BAR_CNTL_STANDARD_64B_BAR_EN;\n+\t\t\t\tregion = \"prefetchable memory\";\n+\t\t\t} else {\n+\t\t\t\taddr_hi = XAL_RC_MEM_32BIT_BASE_HI;\n+\t\t\t\taddr_lo = XAL_RC_MEM_32BIT_BASE_LO;\n+\t\t\t\tlimit_hi = XAL_RC_MEM_32BIT_LIMIT_HI;\n+\t\t\t\tlimit_lo = XAL_RC_MEM_32BIT_LIMIT_LO;\n+\t\t\t\tenable = XAL_RC_BAR_CNTL_STANDARD_32B_BAR_EN;\n+\t\t\t\tregion = \"memory\";\n+\t\t\t}\n+\n+\t\t\tmask = SZ_1M - 1;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* not interested in anything that's not I/O or memory */\n+\t\tif (!region)\n+\t\t\tcontinue;\n+\n+\t\t/* don't check regions that haven't been enabled */\n+\t\tvalue = readl(pcie->xal + XAL_RC_BAR_CNTL_STANDARD);\n+\t\tif ((value & enable) == 0)\n+\t\t\tcontinue;\n+\n+\t\thi = readl(pcie->xal + addr_hi);\n+\t\tlo = readl(pcie->xal + addr_lo);\n+\t\tphys = hi << 32 | lo;\n+\n+\t\thi = readl(pcie->xal + limit_hi);\n+\t\tlo = readl(pcie->xal + limit_lo);\n+\t\tlimit = hi << 32 | lo | mask;\n+\n+\t\tif (phys != start || limit != end) {\n+\t\t\tdev_err(pcie->dev,\n+\t\t\t\t\"%s region mismatch: %pap-%pap -> %pap-%pap\\n\",\n+\t\t\t\tregion, &phys, &limit, &start, &end);\n+\t\t\tstatus = false;\n+\t\t}\n+\t}\n+\n+\tres = platform_get_resource_byname(pdev, IORESOURCE_MEM, \"ecam\");\n+\tif (!res)\n+\t\treturn false;\n+\n+\thi = readl(pcie->xal + XAL_RC_ECAM_BASE_HI);\n+\tlo = readl(pcie->xal + XAL_RC_ECAM_BASE_LO);\n+\tphys = hi << 32 | lo;\n+\n+\tvalue = readl(pcie->xal + XAL_RC_ECAM_BUSMASK);\n+\tlimit = phys + ((value + 1) << 20) - 1;\n+\n+\tif (phys != res->start || limit != res->end) {\n+\t\tdev_err(pcie->dev,\n+\t\t\t\"ECAM region mismatch: %pap-%pap -> %pap-%pap\\n\",\n+\t\t\t&phys, &limit, &res->start, &res->end);\n+\t\tstatus = false;\n+\t}\n+\n+\treturn status;\n+}\n+\n+static bool tegra264_pcie_link_up(struct tegra264_pcie *pcie,\n+\t\t\t\t enum pci_bus_speed *speed)\n+{\n+\tu16 value = readw(pcie->ecam + XTL_RC_PCIE_CFG_LINK_STATUS);\n+\n+\tif (value & PCI_EXP_LNKSTA_DLLLA) {\n+\t\tif (speed)\n+\t\t\t*speed = pcie_link_speed[FIELD_GET(PCI_EXP_LNKSTA_CLS,\n+\t\t\t\t\t\t\t value)];\n+\n+\t\treturn true;\n+\t}\n+\n+\treturn false;\n+}\n+\n+static void tegra264_pcie_init(struct tegra264_pcie *pcie)\n+{\n+\tenum pci_bus_speed speed;\n+\tunsigned int i;\n+\tu32 value;\n+\n+\t/* bring the link out of reset */\n+\tvalue = readl(pcie->xtl + XTL_RC_MGMT_PERST_CONTROL);\n+\tvalue |= XTL_RC_MGMT_PERST_CONTROL_PERST_O_N;\n+\twritel(value, pcie->xtl + XTL_RC_MGMT_PERST_CONTROL);\n+\n+\tif (!tegra_is_silicon()) {\n+\t\tdev_info(pcie->dev,\n+\t\t\t \"skipping link state for PCIe #%u in simulation\\n\",\n+\t\t\t pcie->ctl_id);\n+\t\tpcie->link_up = true;\n+\t\treturn;\n+\t}\n+\n+\tfor (i = 0; i < PCIE_LINK_WAIT_MAX_RETRIES; i++) {\n+\t\tif (tegra264_pcie_link_up(pcie, NULL))\n+\t\t\tbreak;\n+\n+\t\tusleep_range(PCIE_LINK_WAIT_US_MIN, PCIE_LINK_WAIT_US_MAX);\n+\t}\n+\n+\tif (tegra264_pcie_link_up(pcie, &speed)) {\n+\t\t/* Per PCIe r5.0, 6.6.1 wait for 100ms after DLL up */\n+\t\tmsleep(PCIE_RESET_CONFIG_WAIT_MS);\n+\n+\t\tdev_info(pcie->dev, \"PCIe #%u link is up (speed: %s)\\n\",\n+\t\t\t pcie->ctl_id, pci_speed_string(speed));\n+\t\ttegra264_pcie_icc_set(pcie);\n+\t\tpcie->link_up = true;\n+\t} else {\n+\t\tdev_info(pcie->dev, \"PCIe #%u link is down\\n\", pcie->ctl_id);\n+\n+\t\tvalue = readl(pcie->xtl + XTL_RC_MGMT_CLOCK_CONTROL);\n+\n+\t\t/*\n+\t\t * Set link state only when link fails and no hot-plug feature\n+\t\t * is present.\n+\t\t */\n+\t\tif ((value & XTL_RC_MGMT_CLOCK_CONTROL_PEX_CLKREQ_I_N_PIN_USE_CONV_TO_PRSNT) == 0) {\n+\t\t\tdev_info(pcie->dev,\n+\t\t\t\t \"PCIe #%u link is down and not hotplug-capable, turning off\\n\",\n+\t\t\t\t pcie->ctl_id);\n+\t\t\ttegra264_pcie_bpmp_set_rp_state(pcie);\n+\t\t\tpcie->link_up = false;\n+\t\t} else {\n+\t\t\tpcie->link_up = true;\n+\t\t}\n+\t}\n+}\n+\n+static int tegra264_pcie_probe(struct platform_device *pdev)\n+{\n+\tstruct device *dev = &pdev->dev;\n+\tstruct pci_host_bridge *bridge;\n+\tstruct tegra264_pcie *pcie;\n+\tstruct resource_entry *bus;\n+\tstruct resource *res;\n+\tint err;\n+\n+\tbridge = devm_pci_alloc_host_bridge(dev, sizeof(struct tegra264_pcie));\n+\tif (!bridge)\n+\t\treturn dev_err_probe(dev, -ENOMEM,\n+\t\t\t\t \"failed to allocate host bridge\\n\");\n+\n+\tpcie = pci_host_bridge_priv(bridge);\n+\tplatform_set_drvdata(pdev, pcie);\n+\tpcie->bridge = bridge;\n+\tpcie->dev = dev;\n+\n+\terr = pinctrl_pm_select_default_state(dev);\n+\tif (err < 0)\n+\t\treturn dev_err_probe(dev, err,\n+\t\t\t\t \"failed to configure sideband pins\\n\");\n+\n+\terr = tegra264_pcie_parse_dt(pcie);\n+\tif (err < 0)\n+\t\treturn dev_err_probe(dev, err, \"failed to parse device tree\");\n+\n+\tpcie->xal = devm_platform_ioremap_resource_byname(pdev, \"xal\");\n+\tif (IS_ERR(pcie->xal))\n+\t\treturn dev_err_probe(dev, PTR_ERR(pcie->xal),\n+\t\t\t\t \"failed to map XAL memory\\n\");\n+\n+\tpcie->xtl = devm_platform_ioremap_resource_byname(pdev, \"xtl-pri\");\n+\tif (IS_ERR(pcie->xtl))\n+\t\treturn dev_err_probe(dev, PTR_ERR(pcie->xtl),\n+\t\t\t\t \"failed to map XTL-PRI memory\\n\");\n+\n+\tbus = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);\n+\tif (!bus)\n+\t\treturn dev_err_probe(dev, -ENODEV,\n+\t\t\t\t \"failed to get bus resources\\n\");\n+\n+\tres = platform_get_resource_byname(pdev, IORESOURCE_MEM, \"ecam\");\n+\tif (!res)\n+\t\treturn dev_err_probe(dev, -ENXIO,\n+\t\t\t\t \"failed to get ECAM resource\\n\");\n+\n+\tpcie->icc_path = devm_of_icc_get(&pdev->dev, \"write\");\n+\tif (IS_ERR(pcie->icc_path))\n+\t\treturn dev_err_probe(&pdev->dev, PTR_ERR(pcie->icc_path),\n+\t\t\t\t \"failed to get ICC\");\n+\n+\t/*\n+\t * Parse BPMP property only for silicon, as interaction with BPMP is\n+\t * not needed for other platforms.\n+\t */\n+\tif (tegra_is_silicon()) {\n+\t\tpcie->bpmp = tegra_bpmp_get_with_id(dev, &pcie->ctl_id);\n+\t\tif (IS_ERR(pcie->bpmp))\n+\t\t\treturn dev_err_probe(dev, PTR_ERR(pcie->bpmp),\n+\t\t\t\t\t \"failed to get BPMP\\n\");\n+\t}\n+\n+\tpm_runtime_enable(dev);\n+\tpm_runtime_get_sync(dev);\n+\n+\t/* sanity check that programmed ranges match what's in DT */\n+\tif (!tegra264_pcie_check_ranges(pdev)) {\n+\t\terr = -EINVAL;\n+\t\tgoto put_pm;\n+\t}\n+\n+\tpcie->cfg = pci_ecam_create(dev, res, bus->res, &pci_generic_ecam_ops);\n+\tif (IS_ERR(pcie->cfg)) {\n+\t\terr = dev_err_probe(dev, PTR_ERR(pcie->cfg),\n+\t\t\t\t \"failed to create ECAM\\n\");\n+\t\tgoto put_pm;\n+\t}\n+\n+\tbridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops;\n+\tbridge->sysdata = pcie->cfg;\n+\tpcie->ecam = pcie->cfg->win;\n+\n+\ttegra264_pcie_init(pcie);\n+\n+\tif (!pcie->link_up)\n+\t\tgoto free;\n+\n+\terr = pci_host_probe(bridge);\n+\tif (err < 0) {\n+\t\tdev_err(dev, \"failed to register host: %pe\\n\", ERR_PTR(err));\n+\t\tgoto free;\n+\t}\n+\n+\treturn err;\n+\n+free:\n+\tpci_ecam_free(pcie->cfg);\n+put_pm:\n+\tpm_runtime_put_sync(dev);\n+\tpm_runtime_disable(dev);\n+\n+\tif (tegra_is_silicon())\n+\t\ttegra_bpmp_put(pcie->bpmp);\n+\n+\treturn err;\n+}\n+\n+static void tegra264_pcie_remove(struct platform_device *pdev)\n+{\n+\tstruct tegra264_pcie *pcie = platform_get_drvdata(pdev);\n+\n+\tpci_lock_rescan_remove();\n+\tpci_stop_root_bus(pcie->bridge->bus);\n+\tpci_remove_root_bus(pcie->bridge->bus);\n+\tpci_unlock_rescan_remove();\n+\n+\tpm_runtime_put_sync(&pdev->dev);\n+\tpm_runtime_disable(&pdev->dev);\n+\n+\tif (tegra_is_silicon())\n+\t\ttegra_bpmp_put(pcie->bpmp);\n+\n+\tpci_ecam_free(pcie->cfg);\n+}\n+\n+static int tegra264_pcie_suspend_noirq(struct device *dev)\n+{\n+\tstruct tegra264_pcie *pcie = dev_get_drvdata(dev);\n+\tint err;\n+\n+\tif (pcie->wake_gpio && device_may_wakeup(dev)) {\n+\t\terr = enable_irq_wake(pcie->wake_irq);\n+\t\tif (err < 0)\n+\t\t\tdev_err(dev, \"failed to enable wake IRQ: %pe\\n\",\n+\t\t\t\tERR_PTR(err));\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int tegra264_pcie_resume_noirq(struct device *dev)\n+{\n+\tstruct tegra264_pcie *pcie = dev_get_drvdata(dev);\n+\tint err;\n+\n+\tif (pcie->wake_gpio && device_may_wakeup(dev)) {\n+\t\terr = disable_irq_wake(pcie->wake_irq);\n+\t\tif (err < 0)\n+\t\t\tdev_err(dev, \"failed to disable wake IRQ: %pe\\n\",\n+\t\t\t\tERR_PTR(err));\n+\t}\n+\n+\tif (pcie->link_up == false)\n+\t\treturn 0;\n+\n+\ttegra264_pcie_init(pcie);\n+\n+\treturn 0;\n+}\n+\n+static DEFINE_NOIRQ_DEV_PM_OPS(tegra264_pcie_pm_ops,\n+\t\t\t tegra264_pcie_suspend_noirq,\n+\t\t\t tegra264_pcie_resume_noirq);\n+\n+static const struct of_device_id tegra264_pcie_of_match[] = {\n+\t{\n+\t\t.compatible = \"nvidia,tegra264-pcie\",\n+\t},\n+\t{ /* sentinel */ }\n+};\n+MODULE_DEVICE_TABLE(of, tegra264_pcie_of_match);\n+\n+static struct platform_driver tegra264_pcie_driver = {\n+\t.probe = tegra264_pcie_probe,\n+\t.remove = tegra264_pcie_remove,\n+\t.driver = {\n+\t\t.name = \"tegra264-pcie\",\n+\t\t.pm = &tegra264_pcie_pm_ops,\n+\t\t.of_match_table = tegra264_pcie_of_match,\n+\t},\n+};\n+module_platform_driver(tegra264_pcie_driver);\n+\n+MODULE_AUTHOR(\"Manikanta Maddireddy <mmaddireddy@nvidia.com>\");\n+MODULE_AUTHOR(\"Thierry Reding <treding@nvidia.com>\");\n+MODULE_DESCRIPTION(\"NVIDIA Tegra264 PCIe host controller driver\");\n+MODULE_LICENSE(\"GPL\");\n", "prefixes": [ "v3", "5/6" ] }