{"id":2231947,"url":"http://patchwork.ozlabs.org/api/1.2/patches/2231947/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-gpio/patch/20260501155421.3329862-12-elder@riscstar.com/","project":{"id":42,"url":"http://patchwork.ozlabs.org/api/1.2/projects/42/?format=json","name":"Linux GPIO development","link_name":"linux-gpio","list_id":"linux-gpio.vger.kernel.org","list_email":"linux-gpio@vger.kernel.org","web_url":"","scm_url":"","webscm_url":"","list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20260501155421.3329862-12-elder@riscstar.com>","list_archive_url":null,"date":"2026-05-01T15:54:19","name":"[net-next,11/12] misc: tc956x_pci: add TC956x/QPS615 support","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"f946ee2a8dae480f58db0bd570c9d11acbff0659","submitter":{"id":89551,"url":"http://patchwork.ozlabs.org/api/1.2/people/89551/?format=json","name":"Alex Elder","email":"elder@riscstar.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-gpio/patch/20260501155421.3329862-12-elder@riscstar.com/mbox/","series":[{"id":502478,"url":"http://patchwork.ozlabs.org/api/1.2/series/502478/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-gpio/list/?series=502478","date":"2026-05-01T15:54:09","name":"net: enable TC956x support","version":1,"mbox":"http://patchwork.ozlabs.org/series/502478/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2231947/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2231947/checks/","tags":{},"related":[],"headers":{"Return-Path":"\n <linux-gpio+bounces-35963-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-gpio@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=riscstar-com.20251104.gappssmtp.com\n header.i=@riscstar-com.20251104.gappssmtp.com header.a=rsa-sha256\n header.s=20251104 header.b=AKa5ieJ9;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c15:e001:75::12fc:5321; helo=sin.lore.kernel.org;\n envelope-from=linux-gpio+bounces-35963-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=riscstar-com.20251104.gappssmtp.com\n header.i=@riscstar-com.20251104.gappssmtp.com header.b=\"AKa5ieJ9\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.219.45","smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=riscstar.com","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=riscstar.com"],"Received":["from sin.lore.kernel.org (sin.lore.kernel.org\n [IPv6:2600:3c15:e001:75::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g6bTq0fcKz1xqf\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 02 May 2026 02:05:03 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sin.lore.kernel.org (Postfix) with ESMTP id 2D512303F33B\n\tfor <incoming@patchwork.ozlabs.org>; Fri,  1 May 2026 15:56:49 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 7EAC03E2773;\n\tFri,  1 May 2026 15:55:09 +0000 (UTC)","from mail-qv1-f45.google.com (mail-qv1-f45.google.com\n [209.85.219.45])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id CDBD83E0C75\n\tfor <linux-gpio@vger.kernel.org>; Fri,  1 May 2026 15:55:05 +0000 (UTC)","by mail-qv1-f45.google.com with SMTP id\n 6a1803df08f44-8b3eab6ec9bso37461256d6.1\n        for <linux-gpio@vger.kernel.org>;\n Fri, 01 May 2026 08:55:05 -0700 (PDT)","from zippy.localdomain (c-75-72-117-212.hsd1.mn.comcast.net.\n [75.72.117.212])\n        by smtp.gmail.com with ESMTPSA id\n 6a1803df08f44-8b539aa7293sm26615406d6.22.2026.05.01.08.55.01\n        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n        Fri, 01 May 2026 08:55:04 -0700 (PDT)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1777650909; cv=none;\n b=uzSLPhmscFhBM++pKc2lzdSAkfhGeuP5/v9XNScUp335xS2Hq8Jl4c/DkLiB5Wegrada/TLtELQ8CEBlRpdVxsANiZfGM53dcqRWXiFl6VXS26zt/PS4cGVIoto4rv7EV2pix4Jy1UE0OIsv1XSa+8F0zHFt4Q/X04XsFKRGcKA=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1777650909; c=relaxed/simple;\n\tbh=forzRLWyCfBDKVOI2MzBg0coVCA3/2GJsEyKABozfGM=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=UipJ9Bnlr/rcKH6knb7QeUlI8kL96HixFVG+C+fXYH1TyJiVr+UYqKvfAGAPiUSqNsYoh4heoS96Mkx87nCXSVd9wwHf1Gtx2wUKY0IUk29waPXB8AaEO7yfRpoXsy0L5aDvjd4FBWcvM8ZiRLt1hvMzQ0D5MGqxDx4/WW9T4vc=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=riscstar.com;\n spf=pass smtp.mailfrom=riscstar.com;\n dkim=pass (2048-bit key) header.d=riscstar-com.20251104.gappssmtp.com\n header.i=@riscstar-com.20251104.gappssmtp.com header.b=AKa5ieJ9;\n arc=none smtp.client-ip=209.85.219.45","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=riscstar-com.20251104.gappssmtp.com; s=20251104; t=1777650905;\n x=1778255705; darn=vger.kernel.org;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n         :message-id:reply-to;\n        bh=50TsK4N6iAWHzmW5eczyB3FZ4V18yVei4HQEr+i+4YQ=;\n        b=AKa5ieJ9SiTd0iUyg1x8+srPtItY4J0zkRz+JmMNVz47x4pjSpoAXTuZfQ1Zl5QAEj\n         HX64df7Mj1Nw/ZBS4x5T87iIbI2fH8sb3Qegi5gE5DcKtS7uJwOdnx5BJ5qUu7D730L9\n         4Qte625Ci6IZfGEEknvaBCYnnfQkczDu7no4sst6o3wjrputOaaogRSzh/o7KyZDqxT7\n         2ZDnN3cusuxEV/by+C53rWp/N0HjkQR+xlH4puVBmPlpVs+MA8ATVBhldJnQ8b2jl4Nr\n         rWcV4ftmUJgOa1q1YJCF/ehdei71YrMr9ixTIcP6U3FMpM97eZmzEk8ZW3NA5TzqDh1S\n         EMIg==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=1e100.net; s=20251104; t=1777650905; x=1778255705;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n         :to:cc:subject:date:message-id:reply-to;\n        bh=50TsK4N6iAWHzmW5eczyB3FZ4V18yVei4HQEr+i+4YQ=;\n        b=L1ybMmJk0kzbjuvqcV7ua0qHCXp4TJyEBPasN4Yae/4F3y1gUJU9pFw/m1TDxRd8iR\n         kzuEUIWFxumDcUbFPUTJRscFalsyxEmpGszgjApiENcFIFZLvR5DmPYekh1ONhtqzvpW\n         GrNJT9u7Z4vraztkdDCx3Nzy5Rhe8BulainvUqDB+ORMroy/gcplo9QFxAS0u3EnhRut\n         ANwlTzsn7Qjo8Dou6qF2fueMOjAlY2s1s0oMsSMRqwte3GQlKk0wxMhaGQ/VvzWYtiic\n         mg5hGmPu2hTPXTPAMGxmHvXGYOPFk8Cs2YhPstqqg2ft/My+Fo2EGF1foPVGQts4q7gw\n         Mc/g==","X-Forwarded-Encrypted":"i=1;\n AFNElJ8XO0yX+RdYl+3A8ol/jUb93hEJCu6eCEveh5H7f6lH7NX5Ip7R4gRrRDWLBuqrqu37TSULK5+z/iKG@vger.kernel.org","X-Gm-Message-State":"AOJu0YwoTxAi6sW545Ox6xnff6vRjIwr9WZ1nXnpKVbBRs+Tq6ghfe77\n\tvreJrX5Xkrj/keQASRxuWLHzcG+jzZS2p34aJkW7aimdXpabCuYyvsOksKvP3mvFMZU=","X-Gm-Gg":"AeBDietaPwt3U9A1ZCnHFfMTf6Xq+xsjsmi3musNpQyDDmsP/OJAQRSknfvdsxySLQ3\n\tpm27wGhOJLOpy60q4xinigBDlNw3Nuv5clAcar64595b0bacNlG+1UMmqSMI8VPmWFqI6rXzTFn\n\tTjcphc9Dr4HFr/lamtf453/bZQaxj6n08+5DCCb8a1NWqBcfafEj0KLu1j23fZ1TZAvrY9srrjU\n\trGSsajpTOBPdMTdE7lXYtVLhMiQLsDrn8RLt6k/pu89FYbvZwHa2QtxevJGavkbpquDiXSkbg0/\n\tZyBzItcGvo8aNoZhX8KYCwUj37nL+QU7WiDfieVq9AVyKYZZ3x7HG7KraAWLzUr9gidjuTMmpzI\n\t03S0bQRyj5dTZ0SNJuIcleJ9c5+y98infgMaa4Udf39A7a9LmYZ9Td1C2EzW/NiBX2eNKMaMQ2O\n\tj/77ySXirAGzIBnwDthU92UUjFlGCZzqUWaioTowCv2frEludZBYyvmomtQpptdd5HWvkPwSLVj\n\tpkDMQ==","X-Received":"by 2002:a05:622a:488e:b0:510:45cd:3939 with SMTP id\n d75a77b69052e-51045cd3b6emr22049751cf.5.1777650904662;\n        Fri, 01 May 2026 08:55:04 -0700 (PDT)","From":"Alex Elder <elder@riscstar.com>","To":"andrew+netdev@lunn.ch,\n\tdavem@davemloft.net,\n\tedumazet@google.com,\n\tkuba@kernel.org,\n\tpabeni@redhat.com,\n\tmaxime.chevallier@bootlin.com,\n\trmk+kernel@armlinux.org.uk,\n\tandersson@kernel.org,\n\tkonradybcio@kernel.org,\n\trobh@kernel.org,\n\tkrzk+dt@kernel.org,\n\tconor+dt@kernel.org,\n\tlinusw@kernel.org,\n\tbrgl@kernel.org,\n\tarnd@arndb.de,\n\tgregkh@linuxfoundation.org","Cc":"daniel@riscstar.com,\n\telder@riscstar.com,\n\tmohd.anwar@oss.qualcomm.com,\n\ta0987203069@gmail.com,\n\talexandre.torgue@foss.st.com,\n\tast@kernel.org,\n\tboon.khai.ng@altera.com,\n\tchenchuangyu@xiaomi.com,\n\tchenhuacai@kernel.org,\n\tdaniel@iogearbox.net,\n\thawk@kernel.org,\n\thkallweit1@gmail.com,\n\tinochiama@gmail.com,\n\tjohn.fastabend@gmail.com,\n\tjulianbraha@gmail.com,\n\tlivelycarpet87@gmail.com,\n\tmatthew.gerlach@altera.com,\n\tmcoquelin.stm32@gmail.com,\n\tme@ziyao.cc,\n\tprabhakar.mahadev-lad.rj@bp.renesas.com,\n\trichardcochran@gmail.com,\n\trohan.g.thomas@altera.com,\n\tsdf@fomichev.me,\n\tsiyanteng@cqsoftware.com.cn,\n\tweishangjuan@eswincomputing.com,\n\twens@kernel.org,\n\tnetdev@vger.kernel.org,\n\tbpf@vger.kernel.org,\n\tlinux-arm-msm@vger.kernel.org,\n\tdevicetree@vger.kernel.org,\n\tlinux-gpio@vger.kernel.org,\n\tlinux-stm32@st-md-mailman.stormreply.com,\n\tlinux-arm-kernel@lists.infradead.org,\n\tlinux-kernel@vger.kernel.org","Subject":"[PATCH net-next 11/12] misc: tc956x_pci: add TC956x/QPS615 support","Date":"Fri,  1 May 2026 10:54:19 -0500","Message-ID":"<20260501155421.3329862-12-elder@riscstar.com>","X-Mailer":"git-send-email 2.51.0","In-Reply-To":"<20260501155421.3329862-1-elder@riscstar.com>","References":"<20260501155421.3329862-1-elder@riscstar.com>","Precedence":"bulk","X-Mailing-List":"linux-gpio@vger.kernel.org","List-Id":"<linux-gpio.vger.kernel.org>","List-Subscribe":"<mailto:linux-gpio+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-gpio+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit"},"content":"The Toshiba TC956x is an Ethernet AVB/TSN bridge,  and is\nessentially a small and highly-specialized SoC.  It implements\na number of internal functions, including a GPIO controller,\ncontrol registers managing internal reset and clock control\nsignals, a PCIe switch and internal endpoint, and mapping\nhardware that translates between PCIe and internal addressing.\n\nThe internal PCIe endpoint implements two PCIe functions, each of\nwhich has an attached eMAC.  Each of these eMACs is represented as\ntwo separate devices:  a PCIe function; and the eMAC.  The PCIe\nfunction driver serves as the primary driver, creating other\nassociated devices using the auxiliary bus.\n\nPCIe function 0 is responsible for managing common features on\nthe TC956x chip.  It initializes a \"chip\" data structure that\nkeeps track of common information, and makes that available via\nits platform_data pointer to its PCIe function 1 peer.  It also\nconfigures the address mapping hardware, and sets up an auxiliary\ndevice for the GPIO controller.\n\nAs probing concludes, an auxiliary device is created to represent\nthe eMAC functionality attached to the PCIe function.  A block\nof information is set up to be shared with the auxiliary device.\nIt provides the IRQ to be used by the MAC device, as well as a\nsome memory-mapped I/O pointers and a few other bits of information\nabout the chip.  This information is supplied via the auxiliary\ndevice's platform_data pointer.\n\nCo-developed-by: Daniel Thompson <daniel@riscstar.com>\nSigned-off-by: Daniel Thompson <daniel@riscstar.com>\nSigned-off-by: Alex Elder <elder@riscstar.com>\n---\n drivers/misc/Kconfig      |  10 +\n drivers/misc/Makefile     |   1 +\n drivers/misc/tc956x_pci.c | 667 ++++++++++++++++++++++++++++++++++++++\n 3 files changed, 678 insertions(+)\n create mode 100644 drivers/misc/tc956x_pci.c","diff":"diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig\nindex 00683bf06258f..d021f37129e27 100644\n--- a/drivers/misc/Kconfig\n+++ b/drivers/misc/Kconfig\n@@ -644,6 +644,16 @@ config MCHP_LAN966X_PCI\n \t    - lan966x-miim (MDIO_MSCC_MIIM)\n \t    - lan966x-switch (LAN966X_SWITCH)\n \n+config TOSHIBA_TC956X_PCI\n+\ttristate \"Toshiba TC956X PCI function support\"\n+\tdepends on PCI\n+\tselect AUXILIARY_BUS\n+\thelp\n+\t  This enables support for the two PCI functions implemented by\n+\t  the embedded PCIe endpoint in the Toshiba TC956X.  This driver\n+\t  creates auxiliary devices and requires drivers for these devices\n+\t  to function.\n+\n source \"drivers/misc/c2port/Kconfig\"\n source \"drivers/misc/eeprom/Kconfig\"\n source \"drivers/misc/cb710/Kconfig\"\ndiff --git a/drivers/misc/Makefile b/drivers/misc/Makefile\nindex b32a2597d2467..644d508338382 100644\n--- a/drivers/misc/Makefile\n+++ b/drivers/misc/Makefile\n@@ -75,3 +75,4 @@ obj-$(CONFIG_MCHP_LAN966X_PCI)\t+= lan966x-pci.o\n obj-y\t\t\t\t+= keba/\n obj-y\t\t\t\t+= amd-sbi/\n obj-$(CONFIG_MISC_RP1)\t\t+= rp1/\n+obj-$(CONFIG_TOSHIBA_TC956X_PCI) += tc956x_pci.o\ndiff --git a/drivers/misc/tc956x_pci.c b/drivers/misc/tc956x_pci.c\nnew file mode 100644\nindex 0000000000000..741a0ae0d3afb\n--- /dev/null\n+++ b/drivers/misc/tc956x_pci.c\n@@ -0,0 +1,667 @@\n+// SPDX-License-Identifier: GPL-2.0\n+\n+/*\n+ * Copyright (C) 2026 by RISCstar Solutions Corporation.  All rights reserved.\n+ */\n+\n+/*\n+ * The Toshiba TC956X implements a PCIe Gen 3 switch that connects an\n+ * upstream x4 port to three downstream PCIe ports--two external ones\n+ * and an internal one which implements an internal PCIe endpoint.  The\n+ * endpoint implements two PCIe functions, each having a Synopsys XGMAC\n+ * Ethernet interface.\n+ *\n+ * The TC956X implements other functionality, including an embedded\n+ * MCU, a UART, a GPIO controller, internal resets and clocks, and\n+ * interrupt handling.  These features are separate from (and in some\n+ * cases used by) both Ethernet XGMACs.  Each Ethernet MAC must be\n+ * attached to a working PHY for it to be functional, and for this\n+ * reason either of them (or both!) might not be usable/used.\n+ *\n+ * To support the non-XGMAC functionality on the TC956X regardless of\n+ * the presence of either Ethernet PHY, the Ethernet functions are\n+ * treated as two parts:  a PCIe function; and a Synopsys XGMAC component.\n+ * The PCIe function has access to the BARs used by the XGMAC, and maps\n+ * them for use.  Each XGMAP is treated as an auxiliary sub-device of\n+ * its (parent) PCIe function, and is probed and bound separate from it.\n+ *\n+ * This PCI driver binds to the Toshiba TC956X (physical) PCI function\n+ * (VID 0x1179, DID 0x0220).  There are two of these present on the\n+ * TC956X SoC.  This driver maps the PCI BARs and performs other initial\n+ * setup, then creates auxiliary devices.\n+ *\n+ * Embedded PCI function 0 manages non-MAC functionality.  This includes\n+ * creating and registering the GPIO auxiliary device (if necessary), as\n+ * well as asserting and deasserting internal reset signals and enabling\n+ * and disabling internal clocks.\n+ *\n+ * Both PCI functions create auxiliary devices to implement an Ethernet\n+ * XGMAC.  A block of data (struct tc956x_dwmac_data) is shared using\n+ * the auxiliary device's platform data with the stmmac driver that\n+ * binds to the XGMAC auxiliary device.  This includes a number of\n+ * pointers to memory regions used by the stmmac driver.\n+ */\n+\n+#include <linux/auxiliary_bus.h>\n+#include <linux/compiler_types.h>\n+#include <linux/device.h>\n+#include <linux/dev_printk.h>\n+#include <linux/init.h>\n+#include <linux/io.h>\n+#include <linux/module.h>\n+#include <linux/of.h>\n+#include <linux/pci.h>\n+#include <linux/property.h>\n+#include <linux/regmap.h>\n+#include <linux/types.h>\n+\n+#include <soc/toshiba/tc956x-dwmac.h>\n+\n+#define DRIVER_NAME\t\t\tTC956X_PCIE_DRIVER_NAME\n+\n+#define GPIO_DEVICE_NAME\t\t\"tc9564-gpio\"\n+\n+#define PCI_DEVICE_ID_TOSHIBA_TC956X\t0x0220\n+\n+/* PCI BAR assignments */\n+#define PCI_BAR_BRIDGE_CONFIG\t\t0\t/* For TAMAP */\n+#define PCI_BAR_SFR\t\t\t4\t/* For all other features */\n+\n+/* Chip and revision ID register */\n+#define NCID_OFFSET\t\t\t0x0000\n+#define NCID_REV_ID_MASK\t\tGENMASK(7, 0)\n+\n+/* Reset and clock register offsets.  MAC resets and clocks are controlled\n+ * by bits in register 0 for MAC0, register 1 for MAC1.  Other non-MAC\n+ * resets and clocks (whose IDs are defined here) are controlled by bits\n+ * in register 0.\n+ *\n+ * These are relative to the base of the clock/reset regmap.\n+ */\n+#define RSTCTRL0_OFFSET\t\t\t0x0008\n+#define RSTCTRL1_OFFSET\t\t\t0x0010\n+#define CLKCTRL0_OFFSET\t\t\t0x0004\n+#define CLKCTRL1_OFFSET\t\t\t0x000c\n+\n+enum reset_id {\n+\tRESET_MCU\t\t= 0,\n+\tRESET_MCU1\t\t= 1,\n+\tRESET_MSIGEN\t\t= 18,\n+\tRESET_INTC\t\t= 4,\n+\tRESET_UART0\t\t= 16,\n+};\n+\n+enum clock_id {\n+\tCLOCK_MCU\t\t= 0,\n+\tCLOCK_SRAM\t\t= 13,\n+\tCLOCK_MSIGEN\t\t= 18,\n+\tCLOCK_PLL\t\t= 24,\n+\tCLOCK_SGMII\t\t= 25,\n+\tCLOCK_REFCLK\t\t= 26,\n+\tCLOCK_INTC\t\t= 4,\n+\tCLOCK_UART0\t\t= 16,\n+};\n+\n+/*\n+ * The TAMAP function has four AXI translation tables each with eight\n+ * 4-byte registers.  The Ethernet MAC accesses PCI resources through\n+ * addressses based at TC956X_SLV00_SRC_ADDR, and the first translation\n+ * table converts those to PCIe address space starting based at 0x0.\n+ * We don't use the other three available TAMAC tables.\n+ */\n+#define ATR_AXI4_SLV0_OFFSET\t\t0x0800\n+#define AXI4_TABLE_ENTRY_COUNT\t\t4\n+#define AXI4_ENTRY_BASE(id)\t\t((id) * AXI4_TABLE_STRIDE)\n+#define AXI4_TABLE_STRIDE               0x20\n+\n+/* Address translation space parameters used for entry 0 */\n+#define SLV00_ATR_SIZE\t\t\t35\t/* 2^36 (64 gigabytes) */\n+/* TC956X_SLV00_SRC_ADDR is the source address, defined in the common header */\n+#define SLV00_TRSL_ADDR\t\t\t0x0000000000000000ULL\n+\n+/* Translation entry registers, fields, and values used */\n+#define SRC_ADDR_LO_OFFSET\t\t0x0000\n+#define ATR_IMPL\t\t\tBIT(0)\t\t/* 1 = enabled */\n+#define ATR_SIZE_MASK\t\t\tGENMASK(6, 1)\t/* size 2^(ATR + 1) */\n+#define SRC_ADDR_HI_OFFSET\t\t0x0004\n+#define TRSL_ADDR_LO_OFFSET\t\t0x0008\n+#define TRSL_ADDR_HI_OFFSET\t\t0x000c\n+#define TRSL_PARAM_OFFSET\t\t0x0010\n+#define TRSL_ID_MASK\t\t\tGENMASK(3, 0)\n+#define TRSL_ID_PCIE_TX_RX\t\t0\n+#define TRSL_PARAM_MASK\t\t\tGENMASK(27, 16)\n+\n+/*\n+ * The TC956X implements an \"SFR\" address space, which provides access\n+ * to *all* internal IP block registers, both MAC and non-MAC.  This\n+ * space is also accessible via an I2C interface used by the PCI pwrctl\n+ * driver (in \"pci-pwrctrl-tc9563.c\"), though that driver accesses the\n+ * range in a very limited way.  For the MAC functions we divide up the\n+ * range, providing specific addresses needed by the stmmac driver.\n+ */\n+#define EMAC_CTL_OFFSET(_mac_id)\t((_mac_id) ? 0x1074 : 0x1070)\n+#define MSIGEN_OFFSET(_mac_id)\t\t((_mac_id) ? 0xf100 : 0xf000)\n+#define DWMAC_OFFSET(_mac_id)\t\t((_mac_id) ? 0x48000 : 0x40000)\n+\n+/*\n+ * struct tc956x_chip - Common information related to the TC956X chip\n+ * @dev:\t\tDevice structure for function 0\n+ * @sfr:\t\tMapped SFR regions (BAR 4, one per PCI function)\n+ * @bridge_config:\tRegmap used for bridge configuration (BAR 0)\n+ * @reset_clock_regmap:\tRegmap used for resets and clocks\n+ * @rev_id:\t\tChip revision ID (for quirks)\n+ */\n+struct tc956x_chip {\n+\tstruct device *dev;\n+\tvoid __iomem *sfr[2];\n+\tvoid __iomem *bridge_config;\n+\tstruct regmap *reset_clock_regmap;\n+\tu8 rev_id;\n+};\n+\n+static const struct regmap_config gpio_regmap_config = {\n+\t.name\t\t= \"tc956x-gpio\",\n+\t.reg_bits\t= 32,\n+\t.reg_stride\t= 4,\n+\t.reg_base\t= 0x1200,\t/* Register GPIOI0 */\n+\t.val_bits\t= 32,\n+\t.max_register\t= 0x1214,\t/* Register GPIOO1 */\n+};\n+\n+static const struct regmap_config reset_clock_regmap_config = {\n+\t.name\t\t= \"tc956x-clk-reset\",\n+\t.reg_bits\t= 32,\n+\t.reg_stride\t= 4,\n+\t.reg_base\t= 0x1000,\t/* Register NCTLSTS */\n+\t.val_bits\t= 32,\n+\t.max_register\t= 0x1010,\t/* Register NRSTCTRL1 */\n+};\n+\n+/* Common clock/reset register update function (also used for MACs) */\n+void tc956x_reset_clock_set(const struct tc956x_chip *chip, bool reset,\n+\t\t\t    bool reg0, bool set, u8 bit)\n+{\n+\tu32 mask = BIT(bit);\n+\tu32 offset;\n+\n+\tif (reset)\n+\t\toffset = reg0 ? RSTCTRL0_OFFSET : RSTCTRL1_OFFSET;\n+\telse\n+\t\toffset = reg0 ? CLKCTRL0_OFFSET : CLKCTRL1_OFFSET;\n+\n+\t/* Note: no need to check for errors on read/write for MMIO regmap */\n+\t(void)regmap_update_bits(chip->reset_clock_regmap, offset, mask,\n+\t\t\t\t set ? mask : 0);\n+}\n+EXPORT_SYMBOL_GPL(tc956x_reset_clock_set);\n+\n+static inline void chip_reset_assert(const struct tc956x_chip *chip,\n+\t\t\t\t     enum reset_id id)\n+{\n+\ttc956x_reset_clock_set(chip, true, true, true, (u8)id);\n+}\n+\n+static inline void chip_reset_deassert(const struct tc956x_chip *chip,\n+\t\t\t\t       enum reset_id id)\n+{\n+\ttc956x_reset_clock_set(chip, true, true, false, (u8)id);\n+}\n+\n+static inline void chip_clock_enable(const struct tc956x_chip *chip,\n+\t\t\t\t     enum clock_id id)\n+{\n+\ttc956x_reset_clock_set(chip, false, true, true, (u8)id);\n+}\n+\n+static inline void chip_clock_disable(const struct tc956x_chip *chip,\n+\t\t\t\t      enum clock_id id)\n+{\n+\ttc956x_reset_clock_set(chip, false, true, false, (u8)id);\n+}\n+\n+static void adev_release(struct device *dev)\n+{\n+\tstruct auxiliary_device *adev = to_auxiliary_dev(dev);\n+\n+\tof_node_put(adev->dev.of_node);\n+\tkfree(adev);\n+}\n+\n+static void adev_remove(void *data)\n+{\n+\tstruct auxiliary_device *adev = data;\n+\n+\tauxiliary_device_delete(adev);\n+\tauxiliary_device_uninit(adev);\n+}\n+\n+static int adev_device_add(struct device *dev, const char *name, u32 id,\n+\t\t\t   void *platform_data)\n+{\n+\tstruct auxiliary_device *adev;\n+\tint ret;\n+\n+\tadev = kzalloc_obj(*adev);\n+\tif (!adev)\n+\t\treturn -ENOMEM;\n+\n+\tadev->id = id;\n+\tadev->name = name;\n+\tadev->dev.parent = dev;\n+\tadev->dev.platform_data = platform_data;\n+\tadev->dev.release = adev_release;\n+\tdevice_set_of_node_from_dev(&adev->dev, dev);\n+\n+\tret = auxiliary_device_init(adev);\n+\tif (ret) {\n+\t\tof_node_put(adev->dev.of_node);\n+\t\tkfree(adev);\n+\t\treturn ret;\n+\t}\n+\n+\tret = auxiliary_device_add(adev);\n+\tif (ret) {\n+\t\tauxiliary_device_uninit(adev);\n+\t\treturn ret;\n+\t}\n+\n+\treturn devm_add_action_or_reset(dev, adev_remove, adev);\n+}\n+\n+/* The embedded GPIO controller has an auxiliary device driver */\n+static int chip_gpio_adev_add(struct tc956x_chip *chip)\n+{\n+\tstruct device *dev = chip->dev;\n+\tstruct regmap *regmap;\n+\n+\t/* If needed, PCIe function 0 implements the GPIO controller. */\n+\tif (!device_property_present(dev, \"gpio-controller\"))\n+\t\treturn 0;\n+\n+\tregmap = devm_regmap_init_mmio(dev, chip->sfr[0], &gpio_regmap_config);\n+\tif (IS_ERR(regmap))\n+\t\treturn PTR_ERR(regmap);\n+\n+\treturn adev_device_add(dev, GPIO_DEVICE_NAME, 0, regmap);\n+}\n+\n+/* The two embedded XGMAC controllers have an auxiliary device driver */\n+static int function_xgmac_adev_add(struct pci_dev *pdev,\n+\t\t\t\t   struct tc956x_chip *chip,\n+\t\t\t\t   unsigned int msigen_irq)\n+{\n+\tu8 mac_id = PCI_FUNC(pdev->devfn);\n+\tstruct device *dev = &pdev->dev;\n+\tstruct tc956x_dwmac_data *data;\n+\tvoid __iomem *sfr;\n+\tint ret;\n+\n+\tif (mac_id > 1)\n+\t\treturn -EINVAL;\n+\tsfr = chip->sfr[mac_id];\n+\n+\tdata = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);\n+\tif (!data)\n+\t\treturn -ENOMEM;\n+\n+\tdata->chip = chip;\n+\tdata->msigen = sfr + MSIGEN_OFFSET(mac_id);\n+\tdata->msigen_irq = msigen_irq;\n+\tdata->emac = sfr + DWMAC_OFFSET(mac_id);\n+\tdata->emac_ctl = sfr + EMAC_CTL_OFFSET(mac_id);\n+\tdata->rev_id = chip->rev_id;\n+\tdata->mac_id = mac_id;\n+\n+\tret = adev_device_add(dev, TC956X_XGMAC_DEV_NAME, mac_id, data);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn 0;\n+}\n+\n+static int chip_reset_clock_init(struct tc956x_chip *chip)\n+{\n+\tvoid __iomem *base = chip->sfr[0];\n+\tstruct device *dev = chip->dev;\n+\tstruct regmap *regmap;\n+\n+\tregmap = devm_regmap_init_mmio(dev, base, &reset_clock_regmap_config);\n+\tif (IS_ERR(regmap))\n+\t\treturn PTR_ERR(regmap);\n+\tchip->reset_clock_regmap = regmap;\n+\n+\treturn 0;\n+}\n+\n+static int chip_tamap_init(struct tc956x_chip *chip, struct pci_dev *pdev)\n+{\n+\tvoid __iomem *base;\n+\n+\tbase = pcim_iomap_region(pdev, PCI_BAR_BRIDGE_CONFIG, DRIVER_NAME);\n+\tif (IS_ERR(base))\n+\t\treturn PTR_ERR(base);\n+\n+\tchip->bridge_config = base + ATR_AXI4_SLV0_OFFSET;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * chip_tamap_config() - Configure the table address map registers\n+ * @chip:\tThe TC956X chip pointer\n+ *\n+ * Populate the registers used to translate AXI bus accesses to PCI TLPs.\n+ * TC956X_SLV00_SRC_ADDR defines the base address of the AXI address range.\n+ * AXI addresses are translated to the PCIe address range, whose base address\n+ * is defined by SLV00_TRSL_ADDR (which is 0x0).\n+ */\n+static void chip_tamap_config(struct tc956x_chip *chip)\n+{\n+\tvoid __iomem *table_base = chip->bridge_config;\n+\tvoid __iomem *entry_base;\n+\tu32 trsl_param_val;\n+\tu32 atr_size_val;\n+\tu32 val;\n+\tu32 i;\n+\n+\t/*\n+\t * The lower bits of the source address must be zero, because the\n+\t * SRC_ADDR_LO register encodes the address translation space size\n+\t * and \"implmented\" bit there.  The size field defines the size of\n+\t * the translation space (2^(ATR_SIZE + 1)).  The minimum size is\n+\t * 4096 bytes, so ATR_SIZE value must be 11 or more.\n+\t */\n+\tBUILD_BUG_ON(!!u32_get_bits(lower_32_bits(TC956X_SLV00_SRC_ADDR),\n+\t\t\t\t\t\t  ATR_SIZE_MASK));\n+\tBUILD_BUG_ON(TC956X_SLV00_SRC_ADDR & ATR_IMPL);\n+\tBUILD_BUG_ON(SLV00_ATR_SIZE < 11);\n+\n+\t/*\n+\t * We only use the first AXI4 slave TAMAC table:\n+\t *\tEDMA address region:\t0x10 0000 0000 - 0x1f ffff ffff\n+\t *\tis translated to:\t0x00 0000 0000 - 0x0f ffff ffff\n+\t */\n+\tentry_base = table_base + AXI4_ENTRY_BASE(0);\n+\n+\tatr_size_val = u32_encode_bits(SLV00_ATR_SIZE, ATR_SIZE_MASK);\n+\tatr_size_val |= ATR_IMPL;\n+\tval = lower_32_bits(TC956X_SLV00_SRC_ADDR) | atr_size_val;\n+\twritel(val, entry_base + SRC_ADDR_LO_OFFSET);\n+\n+\tval = upper_32_bits(TC956X_SLV00_SRC_ADDR);\n+\twritel(val, entry_base + SRC_ADDR_HI_OFFSET);\n+\n+\tval = lower_32_bits(SLV00_TRSL_ADDR);\n+\twritel(val, entry_base + TRSL_ADDR_LO_OFFSET);\n+\n+\tval = upper_32_bits(SLV00_TRSL_ADDR);\n+\twritel(val, entry_base + TRSL_ADDR_HI_OFFSET);\n+\n+\t/* This TRSL_PARAM value is assigned for all four TAMAC tables */\n+\ttrsl_param_val = u32_encode_bits(TRSL_ID_PCIE_TX_RX, TRSL_ID_MASK);\n+\n+\twritel(trsl_param_val, entry_base + TRSL_PARAM_OFFSET);\n+\n+\t/* Set all other unused entries to default values (no translation) */\n+\tfor (i = 1; i < AXI4_TABLE_ENTRY_COUNT; i++) {\n+\t\tentry_base = table_base + AXI4_ENTRY_BASE(i);\n+\n+\t\twritel(0x0, entry_base + SRC_ADDR_LO_OFFSET);\n+\t\twritel(0x0, entry_base + SRC_ADDR_HI_OFFSET);\n+\t\twritel(0x0, entry_base + TRSL_ADDR_LO_OFFSET);\n+\t\twritel(0x0, entry_base + TRSL_ADDR_HI_OFFSET);\n+\t\twritel(trsl_param_val, entry_base + TRSL_PARAM_OFFSET);\n+\t}\n+}\n+\n+static void chip_msigen_enable(struct tc956x_chip *chip)\n+{\n+\tchip_clock_enable(chip, CLOCK_MSIGEN);\n+\tchip_reset_deassert(chip, RESET_MSIGEN);\n+}\n+\n+static void chip_msigen_disable(struct tc956x_chip *chip)\n+{\n+\tchip_reset_assert(chip, RESET_MSIGEN);\n+\tchip_clock_disable(chip, CLOCK_MSIGEN);\n+}\n+\n+static void chip_init_state(struct tc956x_chip *chip)\n+{\n+\t/* The only IP block we currently use is MSIGEN */\n+\tchip_reset_assert(chip, RESET_MCU);\n+\tchip_reset_assert(chip, RESET_MCU1);\n+\tchip_reset_assert(chip, RESET_INTC);\n+\tchip_reset_assert(chip, RESET_UART0);\n+\tchip_clock_disable(chip, CLOCK_MCU);\n+\tchip_clock_disable(chip, CLOCK_SRAM);\n+\tchip_clock_disable(chip, CLOCK_PLL);\n+\tchip_clock_disable(chip, CLOCK_SGMII);\n+\tchip_clock_disable(chip, CLOCK_REFCLK);\n+\tchip_clock_disable(chip, CLOCK_INTC);\n+\tchip_clock_disable(chip, CLOCK_UART0);\n+\n+\t/* Start with MSIGEN in reset with its clock disabled */\n+\tchip_msigen_disable(chip);\n+}\n+\n+static void chip_link_del(void *data)\n+{\n+\tstruct device_link *link = data;\n+\n+\tdevice_link_del(link);\n+}\n+\n+/*\n+ * Function 0 will allocate the chip structure that is shared by both\n+ * functions.  Once it has allocated the structure it assigns it as\n+ * the PCI device platform data.  Function 1 can access the shared\n+ * chip structure by looking up the function 0 device to use its\n+ * platform data..\n+ *\n+ * Returns a chip structure pointer, or a pointer-coded error.\n+ */\n+static struct tc956x_chip *chip_get(struct pci_dev *pdev)\n+{\n+\tunsigned int devfn = pdev->devfn;\n+\tstruct device *dev = &pdev->dev;\n+\tstruct tc956x_chip *chip;\n+\tstruct device_link *link;\n+\tstruct pci_dev *peer;\n+\tint ret;\n+\n+\t/* Function 0 just allocates the chip structure */\n+\tif (!PCI_FUNC(devfn)) {\n+\t\tchip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);\n+\t\tif (!chip)\n+\t\t\treturn ERR_PTR(-ENOMEM);\n+\n+\t\t/*\n+\t\t * The function whose device pointer matches the chip's\n+\t\t * device pointer manages common resources (like MSIGEN).\n+\t\t */\n+\t\tchip->dev = dev;\n+\n+\t\treturn chip;\n+\t}\n+\n+\t/* Function 1 has to get the chip structure from function 0 */\n+\tpeer = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(devfn), 0));\n+\tif (!peer)\n+\t\treturn ERR_PTR(-ENXIO);\n+\n+\t/* If function 0 hasn't set up the chip yet, try again later */\n+\tchip = dev_get_platdata(&peer->dev);\n+\tif (!chip)\n+\t\treturn ERR_PTR(-EPROBE_DEFER);\n+\n+\t/* Mark function 1's device as dependent on function 0 */\n+\tlink = device_link_add(dev, &peer->dev, DL_FLAG_STATELESS);\n+\tif (!link)\n+\t\treturn ERR_PTR(-ENODEV);\n+\n+\tret = devm_add_action_or_reset(&peer->dev, chip_link_del, link);\n+\tif (ret)\n+\t\treturn ERR_PTR(ret);\n+\n+\treturn chip;\n+}\n+\n+static int chip_init(struct tc956x_chip *chip, struct pci_dev *pdev)\n+{\n+\tu32 id = PCI_FUNC(pdev->devfn) ? 1 : 0;\n+\tu32 val;\n+\tint ret;\n+\n+\t/* Both chips need to map their SFR region */\n+\tchip->sfr[id] = pcim_iomap_region(pdev, PCI_BAR_SFR, DRIVER_NAME);\n+\tif (IS_ERR(chip->sfr[id]))\n+\t\treturn PTR_ERR(chip->sfr[id]);\n+\n+\t/* Function 0 handles common initialization */\n+\tif (id)\n+\t\treturn 0;\n+\n+\tret = chip_tamap_init(chip, pdev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = chip_reset_clock_init(chip);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tchip_init_state(chip);\n+\n+\tret = chip_gpio_adev_add(chip);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* Get the revision ID */\n+\tval = readl(chip->sfr[0] + NCID_OFFSET);\n+\tchip->rev_id = u32_get_bits(val, NCID_REV_ID_MASK);\n+\n+\tchip_tamap_config(chip);\n+\tchip_msigen_enable(chip);\n+\n+\treturn 0;\n+}\n+\n+static int\n+tc956x_function_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n+{\n+\tstruct device *dev = &pdev->dev;\n+\tstruct tc956x_chip *chip;\n+\tunsigned int msigen_irq;\n+\tint ret;\n+\n+\t/* Despite being a PCI device, we require devicetree */\n+\tif (!dev->of_node)\n+\t\treturn -EINVAL;\n+\n+\tret = pcim_enable_device(pdev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tpci_set_master(pdev);\n+\n+\t/* Function 1 gets -EPROBE_DEFER until function 0 sets platform data */\n+\tchip = chip_get(pdev);\n+\tif (IS_ERR(chip))\n+\t\treturn dev_err_probe(dev, PTR_ERR(chip), \"failed to get chip\\n\");\n+\n+\t/* We called pcim_enable_device() so this will be freed automatically */\n+\tret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);\n+\tif (ret < 1)\n+\t\treturn dev_err_probe(dev, ret ? : -EIO,\n+\t\t\t\t     \"failed to allocate IRQ vectors\\n\");\n+\n+\tret = pci_irq_vector(pdev, 0);\n+\tif (ret < 1)\n+\t\treturn dev_err_probe(dev, ret ? : -EIO, \"failed to get IRQ\\n\");\n+\tmsigen_irq = ret;\n+\n+\tret = chip_init(chip, pdev);\n+\tif (ret)\n+\t\treturn dev_err_probe(dev, ret, \"failed to initialize chip\\n\");\n+\n+\t/* We're ready; the other function can now probe */\n+\tdev->platform_data = chip;\n+\n+\tret = function_xgmac_adev_add(pdev, chip, msigen_irq);\n+\tif (ret)\n+\t\treturn dev_err_probe(dev, ret, \"failed to add xgmap device\\n\");\n+\n+\treturn 0;\n+}\n+\n+static void tc956x_function_remove(struct pci_dev *pdev)\n+{\n+\tstruct tc956x_chip *chip = dev_get_platdata(&pdev->dev);\n+\n+\tpci_clear_master(pdev);\n+\n+\tif (&pdev->dev == chip->dev)\n+\t\tchip_msigen_disable(chip);\n+}\n+\n+static const struct pci_device_id tc956x_function_id_table[] = {\n+\t{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TC956X), },\n+\t{ },\n+};\n+MODULE_DEVICE_TABLE(pci, tc956x_function_id_table);\n+\n+static int tc956x_chip_suspend_noirq(struct device *dev)\n+{\n+\tstruct tc956x_chip *chip = dev_get_platdata(dev);\n+\tstruct pci_dev *pdev = to_pci_dev(dev);\n+\n+\tif (dev == chip->dev)\n+\t\tchip_msigen_disable(chip);\n+\n+\t/* It seems most callers ignore the return value here */\n+\tpci_save_state(pdev);\n+\tpci_wake_from_d3(pdev, true);\n+\n+\treturn 0;\n+}\n+\n+static int tc956x_chip_resume_noirq(struct device *dev)\n+{\n+\tstruct tc956x_chip *chip = dev_get_platdata(dev);\n+\tstruct pci_dev *pdev = to_pci_dev(dev);\n+\n+\tpci_wake_from_d3(pdev, false);\n+\tpci_set_power_state(pdev, PCI_D0);\n+\tpci_restore_state(pdev);\n+\n+\tif (dev != chip->dev)\n+\t\treturn 0;\n+\n+\t/* Reconfigure tamap tables following suspend */\n+\tchip_tamap_config(chip);\n+\n+\tchip_msigen_enable(chip);\n+\n+\treturn 0;\n+}\n+\n+static DEFINE_NOIRQ_DEV_PM_OPS(tc956x_chip_pm_ops,\n+\t\t\t       tc956x_chip_suspend_noirq,\n+\t\t\t       tc956x_chip_resume_noirq);\n+\n+static struct pci_driver tc956x_function_driver = {\n+\t.name\t\t= DRIVER_NAME,\n+\t.id_table\t= tc956x_function_id_table,\n+\t.probe\t\t= tc956x_function_probe,\n+\t.remove\t\t= tc956x_function_remove,\n+\t.driver\t\t= {\n+\t\t.name\t\t= DRIVER_NAME,\n+\t\t.owner\t\t= THIS_MODULE,\n+\t\t.pm\t\t= pm_sleep_ptr(&tc956x_chip_pm_ops),\n+\t},\n+};\n+\n+module_pci_driver(tc956x_function_driver);\n+\n+MODULE_DESCRIPTION(\"Toshiba TC956X PCIe Embedded Function Driver\");\n+MODULE_LICENSE(\"GPL\");\n","prefixes":["net-next","11/12"]}