Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2231946/?format=api
{ "id": 2231946, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2231946/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-gpio/patch/20260501155421.3329862-11-elder@riscstar.com/", "project": { "id": 42, "url": "http://patchwork.ozlabs.org/api/1.1/projects/42/?format=api", "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": "" }, "msgid": "<20260501155421.3329862-11-elder@riscstar.com>", "date": "2026-05-01T15:54:18", "name": "[net-next,10/12] net: stmmac: tc956x: add TC956x/QPS615 support", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "442a3646b8ce5698bd037a3b46a46730f876190e", "submitter": { "id": 89551, "url": "http://patchwork.ozlabs.org/api/1.1/people/89551/?format=api", "name": "Alex Elder", "email": "elder@riscstar.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-gpio/patch/20260501155421.3329862-11-elder@riscstar.com/mbox/", "series": [ { "id": 502478, "url": "http://patchwork.ozlabs.org/api/1.1/series/502478/?format=api", "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/2231946/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2231946/checks/", "tags": {}, "headers": { "Return-Path": "\n <linux-gpio+bounces-35962-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=GEhor2Xh;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=172.105.105.114; helo=tor.lore.kernel.org;\n envelope-from=linux-gpio+bounces-35962-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=\"GEhor2Xh\"", "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.219.54", "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 tor.lore.kernel.org (tor.lore.kernel.org [172.105.105.114])\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 4g6bTN1x1cz1yHZ\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 02 May 2026 02:04:40 +1000 (AEST)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby tor.lore.kernel.org (Postfix) with ESMTP id EF7CF303B4FD\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 1 May 2026 15:56:35 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 1AAA53D75BC;\n\tFri, 1 May 2026 15:55:06 +0000 (UTC)", "from mail-qv1-f54.google.com (mail-qv1-f54.google.com\n [209.85.219.54])\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 963683E0255\n\tfor <linux-gpio@vger.kernel.org>; Fri, 1 May 2026 15:55:02 +0000 (UTC)", "by mail-qv1-f54.google.com with SMTP id\n 6a1803df08f44-8a3970f1a0eso21356816d6.2\n for <linux-gpio@vger.kernel.org>;\n Fri, 01 May 2026 08:55:02 -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.54.57\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Fri, 01 May 2026 08:55:00 -0700 (PDT)" ], "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1777650905; cv=none;\n b=oPiV/AGGQ6GiMkaqIgrT7z8Dl9ecaYTOtoDCNfJl3WeEgVE9e6/yPDubnDZaxR9AD10SxGewyTj+EOqda+KVzZhzBx9dsuTurQQv3dWUdrTX+9OyRKMbXwzChqIzf+0EjerQI8Lgf18bRd5L6E55tuE8nbWJy9JRgwPNpaXS8Bg=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1777650905; c=relaxed/simple;\n\tbh=JP+j+6TCICqN/WR7i+VV1XoY2uZyoR7unSKG3xQnVg0=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=glxhh3YKMBWjENNT0rrJ+rT8FcyhkHIpaHOoyTrwbbm+ID6WNX3gybunkcfcLJ5qMxuKsOYLVz/N3F1CdTUshFXd80hCp0iUpjIxWjRj8OBfvvZXBURoN3TlgHSD0N4SD/ORjlfF4AFNO8mhuICL+Fjus7Twkw5Ioa2ftZZghY4=", "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=GEhor2Xh;\n arc=none smtp.client-ip=209.85.219.54", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=riscstar-com.20251104.gappssmtp.com; s=20251104; t=1777650902;\n x=1778255702; 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=TLtmgJRm59utBOLEfAtowzngTeaKeZzm+b79FRaQwf0=;\n b=GEhor2Xhchs9e/VAinzpBGhWZkOhnOlYVFAKavBdVbF4CiEDhjWXzAZey/uZ2zfAH8\n 3GABSRnh19s9dxYDxtUpQbd5n+ZKePAEcc2RyjM9zZUXxSjzLLt9YhHtsDd5TgYHQPUL\n RPQuP6uIwxaVQoidXTe/7UPk/fTZLmlDHRfDlDVta5lAYtM0gzpIwr8jeW9nDNqPeaFJ\n 0Hk5/5L5LDeJWZ6+ubHXHQSuKFxW/pj1/RHVaVeTC8vLx9NHu04O26LEZ7TbvSAnONqR\n CGNv5zSKE735vWle+QIVGAor3nS2uhyH+WRavkPYM2CqUOke/5nuD9mt6S67ht7JL+IF\n HgSQ==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1777650902; x=1778255702;\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=TLtmgJRm59utBOLEfAtowzngTeaKeZzm+b79FRaQwf0=;\n b=FOq9YOVazAM2+B3qW+ZQna0X10RYE99kN+pkIBy2ZaEln+7s0He3VsI6jxjEIHcR3Q\n 0oo3fMZxtW9sOzjKSZIXf09HEpJy+iPRxcS64KyyxqFLHNO1kCte9kpeEyWoYBjmhoDN\n as5LngBtG8PKZ9utYiLoLrCSgDTQ/MWWlnHTyUTlfrCeW19nZWAfnUCwqRiA371bi8OF\n YTXs+ErIXHmz1qcTtiw2xUfG8fdCOgW8cesb2oNVbCeUsuXe992EKo31/OmN4X/qCsDn\n UwqhyXEk5n18jLn0E2vhqiJkzGubnV8raORY37CY+piELafHqV140gGo6pjhS3aHNL5L\n rC7w==", "X-Forwarded-Encrypted": "i=1;\n AFNElJ9bKj261iz9DKLBUYfi4cd17JMHYKZswKHigZhEstZJi0RuzJKdoPI4+hbQvcRgduhoMfhl6GS2mny2@vger.kernel.org", "X-Gm-Message-State": "AOJu0Yz4qBH/6AejC1PGWQkHwTYkdfZRuRNIgl+x3J2FsQ+M/pnMOBo9\n\tguoCC4NaVaM9MxFxePn4i3sUv31//QQnsn6yg2Pjet3qxU+aJo9y7mYCIEl9yEwl1pY=", "X-Gm-Gg": "AeBDieuusue0IEms85mjOldI/Q8CBt1c2Z9xN0Vj2cCs0sqoKs750RtHP+JDOXIS5K6\n\t2Ukv/UaxCVDKTF2+UDCrrotYkPKNBDCQZ+QsqfCvvFLry5tvSatGuNv7T/UjIsGc+2AJ5baARbV\n\t5WhjWuRGts+7Keexqs9i1n/yBfu845u/eynqqrx7PjH8v5gFwaM8bhUBxICfBdfiC/iGjqctw+A\n\tAJ9lxwr87hTFAqz5otWxLWjEPZtytAknRvylRlTgvFs1hB+cxj6u+xR3yWF1ti1aAH3doRzbUty\n\tEVPuP1QcyNycvgCRJBsacCFE4xhv/7KtecF1tYVF6w18HF5KB+pBSmARBbKO1IPET8Um4CsYLam\n\toZ0zo+kxLbkKstjGYlKeeM+5ZQWZUSrT8ci/4M/u/GdghiHm4exbxSGwaEZ9s4rwwaMc8f1KER3\n\tD1UsXbGmlaxQpAybKOP7aHQIw0Tq8T4hB+AnVZGUA7JReyCSwVM8TE8C73CkOzvUKuBnyM6pn5l\n\tXkqCg==", "X-Received": "by 2002:a05:6214:4802:b0:8ae:652b:e3c4 with SMTP id\n 6a1803df08f44-8b668d0b700mr535566d6.49.1777650901165;\n Fri, 01 May 2026 08:55:01 -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 Thompson <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 10/12] net: stmmac: tc956x: add TC956x/QPS615 support", "Date": "Fri, 1 May 2026 10:54:18 -0500", "Message-ID": "<20260501155421.3329862-11-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": "From: Daniel Thompson <daniel@riscstar.com>\n\nToshiba TC956x is an Ethernet AVB/TSN bridge and is essentially a\nsmall and highly-specialized SoC. TC956x includes an \"eMAC\" subsystem\nthat can be accessed, along with several other peripherals, via two\nPCIe endpoint functions. There is a main driver for the endpoint that\ndecomposes things and creates auxiliary bus devices to model the SoC.\n\nThe eMAC consists of a Designware XGMAC, XPCS and PMA. Each eMAC is\nsupported by an MSIGEN that bridges TC956x level interrupts to PCIe\nMSIs.\n\nAdd a driver for the eMAC/MSIGEN combination.\n\nCo-developed-by: Alex Elder <elder@riscstar.com>\nSigned-off-by: Alex Elder <elder@riscstar.com>\nSigned-off-by: Daniel Thompson <daniel@riscstar.com>\n---\n drivers/net/ethernet/stmicro/stmmac/Kconfig | 13 +\n drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +\n .../ethernet/stmicro/stmmac/dwmac-tc956x.c | 791 ++++++++++++++++++\n include/soc/toshiba/tc956x-dwmac.h | 84 ++\n 4 files changed, 890 insertions(+)\n create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-tc956x.c\n create mode 100644 include/soc/toshiba/tc956x-dwmac.h", "diff": "diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig\nindex e3dd5adda5aca..66bcfaccbe21f 100644\n--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig\n+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig\n@@ -404,6 +404,19 @@ config DWMAC_MOTORCOMM\n \t This enables glue driver for Motorcomm DWMAC-based PCI Ethernet\n \t controllers. Currently only YT6801 is supported.\n \n+config DWMAC_TC956X\n+\ttristate \"Toshiba TC956X DWMAC support\"\n+\tdepends on PCI\n+\tdepends on COMMON_CLK\n+\tdepends on TOSHIBA_TC956X_PCI\n+\tdefault m if TOSHIBA_TC956X_PCI\n+\thelp\n+\t This selects the Toshiba TC956X (and Qualcomm QPS615) support in the\n+\t stmmac driver.\n+\n+\t This provides support for the ethernet controllers found on these\n+\t devices.\n+\n config STMMAC_PCI\n \ttristate \"STMMAC PCI bus support\"\n \tdepends on PCI\ndiff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile\nindex a1cea2f57252e..e8e7f95dbe3e8 100644\n--- a/drivers/net/ethernet/stmicro/stmmac/Makefile\n+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile\n@@ -51,4 +51,6 @@ obj-$(CONFIG_STMMAC_PCI)\t+= stmmac-pci.o\n obj-$(CONFIG_DWMAC_INTEL)\t+= dwmac-intel.o\n obj-$(CONFIG_DWMAC_LOONGSON)\t+= dwmac-loongson.o\n obj-$(CONFIG_DWMAC_MOTORCOMM)\t+= dwmac-motorcomm.o\n+obj-$(CONFIG_TC956X_PCI)\t+= tc956x-pci.o\n+obj-$(CONFIG_DWMAC_TC956X)\t+= dwmac-tc956x.o\n stmmac-pci-objs:= stmmac_pci.o\ndiff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-tc956x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-tc956x.c\nnew file mode 100644\nindex 0000000000000..27ff83dd3bd9e\n--- /dev/null\n+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-tc956x.c\n@@ -0,0 +1,791 @@\n+// SPDX-License-Identifier: GPL-2.0\n+\n+/*\n+ * Copyright (C) 2026 by RISCstar Solutions Corporation. All rights reserved.\n+ *\n+ * Derived from code having the following copyrights:\n+ * Copyright (C) 2011-2012 Vayavya Labs Pvt Ltd\n+ * Copyright (C) 2025 Toshiba Electronic Devices & Storage Corporation\n+ */\n+\n+#include <linux/auxiliary_bus.h>\n+#include <linux/bitops.h>\n+#include <linux/iopoll.h>\n+#include <linux/irqdomain.h>\n+#include <linux/irqchip/chained_irq.h>\n+#include <linux/pcs/pcs-xpcs-regmap.h>\n+#include <linux/pcs/pcs-xpcs.h>\n+#include <linux/phy.h>\n+#include <linux/regmap.h>\n+#include <linux/stmmac.h>\n+#include <linux/types.h>\n+#include <linux/units.h>\n+\n+#include <soc/toshiba/tc956x-dwmac.h>\n+\n+#include \"common.h\"\n+#include \"dwxgmac2.h\"\n+#include \"stmmac.h\"\n+\n+#define DRIVER_NAME\t\t\t\"dwmac-tc956x\"\n+\n+#define TC956X_PTP_CLOCK_RATE\t\t(250 * HZ_PER_MHZ)\n+\n+#define TC956X_RX_FIFO_KB\t\t46\t/* Shared by all RX queues */\n+#define TC956X_TX_FIFO_KB\t\t46\t/* Shared by all TX queues */\n+\n+/* Fields and values for the EMACTL registers */\n+#define EMAC_SP_SEL_MASK\t\tGENMASK(3, 0)\n+#define SP_SEL_SGMII_2500M\t\t4\n+#define SP_SEL_SGMII_1000M\t\t5\n+#define SP_SEL_SGMII_100M\t\t6\n+#define SP_SEL_SGMII_10M\t\t7\n+#define EMAC_PHY_INF_SEL_MASK\t\tGENMASK(5, 4)\n+#define PCS_CLK_PHY\t\t\t1\t/* Clock from PHY */\n+#define EMAC_INV_SGM_SIG_DET\t\tBIT(6)\t/* 1 = polarity inverted */\n+#define EMAC_LPIHWCLKEN\t\t\tBIT(8)\t/* 1 = low power mode */\n+#define EMAC_INIT_DONE\t\t\tBIT(21)\n+\n+/* MSIGEN Registers */\n+#define MSI_OUT_EN_OFFSET\t\t0x0000\n+#define MSI_MASK_CLR_OFFSET\t\t0x000c\n+#define MSI_MASK_VALUE\t\t\tBIT(0)\n+#define MSI_INT_STS_OFFSET\t\t0x0010\n+\n+enum msigen_hwirq {\n+\tHWIRQ_LPI\t\t= 0,\n+\tHWIRQ_PMT\t\t= 1,\n+\tHWIRQ_EVENT\t\t= 2,\n+\tHWIRQ_TX0\t\t= 3,\n+\tHWIRQ_RX0\t\t= 11,\n+\tHWIRQ_XPCS\t\t= 19,\n+\tHWIRQ_PHY\t\t= 20,\n+\tHWIRQ_PFMAILBOX\t\t= 21,\n+\tHWIRQ_MSIREQ_PLS\t= 24\n+};\n+\n+#define HWIRQ_COUNT\t\t\t25\n+\n+/* Offset to the XPCS memory block, relative to the EMAC address range */\n+#define DWMAC_XPCS_OFFSET\t\t0x3a00\n+\n+/* Offset to the PMATOP memory block, relative to the EMAC address range */\n+#define DWMAC_PMATOP_OFFSET\t\t\t0x4000\n+\n+#define PMA_CML_GL_PM_CFG0\t\t\t0x01b8\n+\n+/*\n+ * Five sets three registers must be configured for PMA. The HWT_REFCLK\n+ * registers are each separated by 0x14 bytes. The Common0 configuration\n+ * registers are separated by 0x8 bytes.\n+ */\n+#define PMA_REG_COUNT\t\t\t\t5\n+\n+#define PMA_HWT_REFCK_R_EN\t\t\t0x1080\n+#define PMA_HWT_REFCK_TERM_EN\t\t\t0x1090\n+#define PMA_HWT_REFCK_STRIDE\t\t\t0x0014\n+\n+#define PMA_COMM_CFG_0_1\t\t\t0x1888\n+#define PMA_COMM_CFG_0_1_STRIDE\t\t\t0x0008\n+\n+/* PMA_COMM_CFG_0_1 fields (WRITE_MASK is a field name) */\n+#define COMM_CFG_WRITE_MASK_MASK\t\tGENMASK(16, 9)\n+#define WRITE_MASK_VALUE\t\t\t0xf7\t/* Power-on value */\n+#define COMM_CFG_ENABLE\t\t\t\tBIT(8)\n+#define COMM_CFG_WRITE_DATA_MASK\t\tGENMASK(7, 0)\n+#define WRITE_DATA_VALUE\t\t\t0x04\t/* Power-on value */\n+\n+/**\n+ * struct tc956x_data - Toshiba-specific platform data\n+ * @dev:\t\tDevice pointer\n+ * @irq_domain:\t\tMSIGEN IRQ domain\n+ * @auxbus_data:\tPointer to data passed from the parent device\n+ * @plat:\t\tPointer to our stmmac platform data\n+ * @dma_cfg:\t\tDMA config buffer used by plat_stmmacenet_data\n+ * @mdio_bus_data:\tMDIO bus data used by plat_stmmacenet_data\n+ * @axi:\t\tAXI data used by plat_stmmacenet_data\n+ * @desc:\t\tDMA descriptor data used by mac_device_info\n+ * @dma:\t\tDMA operations data used by mac_device_info\n+ */\n+struct tc956x_data {\n+\tstruct device *dev;\n+\tstruct irq_domain *irq_domain;\n+\tstruct tc956x_dwmac_data *auxbus_data;\n+\tstruct plat_stmmacenet_data *plat;\n+\n+\t/* These three fields are used by the plat_stmmacenet_data structure */\n+\tstruct stmmac_dma_cfg dma_cfg;\n+\tstruct stmmac_mdio_bus_data mdio_bus_data;\n+\tstruct stmmac_axi axi;\n+\n+\t/* These two fields are used by the mac_device_info structure */\n+\tstruct stmmac_desc_ops desc;\n+\tstruct stmmac_dma_ops dma;\n+};\n+\n+struct tc956x_mac_speed {\n+\tphy_interface_t phy_interface;\n+\tint speed;\n+\tu32 sp_sel;\n+};\n+\n+static struct tc956x_mac_speed mac_speed[] = {\n+\t{ PHY_INTERFACE_MODE_2500BASEX,\tSPEED_2500, SP_SEL_SGMII_2500M, },\n+\t{ PHY_INTERFACE_MODE_SGMII,\tSPEED_2500, SP_SEL_SGMII_2500M, },\n+\t{ PHY_INTERFACE_MODE_SGMII,\tSPEED_1000, SP_SEL_SGMII_1000M, },\n+\t{ PHY_INTERFACE_MODE_SGMII,\tSPEED_100, SP_SEL_SGMII_100M, },\n+\t{ PHY_INTERFACE_MODE_SGMII,\tSPEED_10, SP_SEL_SGMII_10M, },\n+};\n+\n+/* TC956x uses indirect addressing so this need only describe a 1KiB range */\n+static const struct regmap_config xpcs_regmap_config = {\n+\t.reg_bits\t= 32,\n+\t.val_bits\t= 32,\n+\t.reg_base\t= 0x00,\t\t/* Minimum XPCS reg offset */\n+\t.max_register\t= 0xff,\t\t/* Register DW_VR_CSR_VIEWPORT */\n+\t.reg_shift\t= REGMAP_UPSHIFT(2),\n+};\n+\n+static void tc956x_msigen_irq_handler(struct irq_desc *desc)\n+{\n+\tstruct irq_domain *irq_domain = irq_desc_get_handler_data(desc);\n+\tstruct irq_chip *chip = irq_desc_get_chip(desc);\n+\tstruct irq_chip_generic *gc;\n+\tunsigned long status;\n+\tunsigned int hwirq;\n+\n+\tgc = irq_get_domain_generic_chip(irq_domain, 0);\n+\n+\tchained_irq_enter(chip, desc);\n+\n+\tstatus = irq_reg_readl(gc, MSI_INT_STS_OFFSET);\n+\tfor_each_set_bit(hwirq, &status, HWIRQ_COUNT)\n+\t\tgeneric_handle_domain_irq(irq_domain, hwirq);\n+\n+\t/*\n+\t * Clear the MSI flag. Most interrupts within TC956X are level-high\n+\t * type. If any interrupts are still asserted then clearing this flag\n+\t * will cause the (edge-triggered) MSI to be regenerated.\n+\t */\n+\tirq_reg_writel(gc, MSI_MASK_VALUE, MSI_MASK_CLR_OFFSET);\n+\n+\tchained_irq_exit(chip, desc);\n+}\n+\n+static int tc956x_msigen_irq_chip_init(struct irq_chip_generic *gc)\n+{\n+\tstruct tc956x_data *td = gc->domain->host_data;\n+\n+\tgc->reg_base = td->auxbus_data->msigen;\n+\tgc->chip_types[0].regs.mask = MSI_OUT_EN_OFFSET;\n+\tgc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;\n+\tgc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;\n+\n+\t/* Disable all interrupts */\n+\tirq_reg_writel(gc, 0, MSI_OUT_EN_OFFSET);\n+\n+\treturn 0;\n+}\n+\n+static void tc956x_msigen_irq_chip_exit(struct irq_chip_generic *gc)\n+{\n+\tirq_reg_writel(gc, 0, MSI_OUT_EN_OFFSET);\n+}\n+\n+static int tc956x_msigen_irq_domain_init(struct irq_domain *irq_domain)\n+{\n+\tstruct tc956x_data *td = irq_domain->host_data;\n+\n+\tirq_set_chained_handler_and_data(td->auxbus_data->msigen_irq,\n+\t\t\t\t\t tc956x_msigen_irq_handler,\n+\t\t\t\t\t irq_domain);\n+\n+\treturn 0;\n+}\n+\n+static void tc956x_msigen_irq_domain_exit(struct irq_domain *irq_domain)\n+{\n+\tstruct tc956x_data *td = irq_domain->host_data;\n+\n+\tirq_set_chained_handler_and_data(td->auxbus_data->msigen_irq,\n+\t\t\t\t\t NULL, NULL);\n+}\n+\n+/* We have one IRQ chip instance with 25 IRQs in its domain */\n+static struct irq_domain *\n+tc956x_msigen_irq_domain_instantiate(struct tc956x_data *td)\n+{\n+\tstruct irq_domain_chip_generic_info dgc_info;\n+\tstruct irq_domain_info info;\n+\n+\tdgc_info.name = \"tc956x-msigen\";\n+\tdgc_info.handler = handle_level_irq;\n+\tdgc_info.irqs_per_chip = HWIRQ_COUNT;\n+\tdgc_info.num_ct = 1;\n+\tdgc_info.init = tc956x_msigen_irq_chip_init;\n+\tdgc_info.exit = tc956x_msigen_irq_chip_exit;\n+\n+\tinfo.domain_flags = IRQ_DOMAIN_FLAG_DESTROY_GC;\n+\tinfo.size = HWIRQ_COUNT;\n+\tinfo.hwirq_max = HWIRQ_COUNT;\n+\tinfo.ops = &irq_generic_chip_ops;\n+\tinfo.host_data = td;\n+\tinfo.dgc_info = &dgc_info;\n+\tinfo.init = tc956x_msigen_irq_domain_init;\n+\tinfo.exit = tc956x_msigen_irq_domain_exit;\n+\n+\treturn devm_irq_domain_instantiate(td->dev, &info);\n+}\n+\n+/**\n+ * tc956x_pma_init() - Initialize PMA\n+ * @td:\tbsp_priv pointer\n+ *\n+ * Initialize (or re-initialize) the PMA, configure the clocks and wait for the\n+ * eMAC to be ready.\n+ */\n+static void tc956x_pma_init(struct tc956x_data *td)\n+{\n+\tconst struct tc956x_chip *chip = td->auxbus_data->chip;\n+\tvoid __iomem *emac_ctl = td->auxbus_data->emac_ctl;\n+\tu32 id = td->auxbus_data->mac_id;\n+\tvoid __iomem *pmatop;\n+\tu32 val;\n+\tu32 i;\n+\n+\t/*\n+\t * When we re-initialize the PMA then the reset will already have\n+\t * been deasserted. We must make sure the PMA reset is asserted before\n+\t * we change the clock settings.\n+\t */\n+\ttc956x_reset_assert(chip, id, MAC_RESET_PMA);\n+\n+\tpmatop = td->auxbus_data->emac + DWMAC_PMATOP_OFFSET;\n+\n+\t/* Power on CML buffer (0 = normal mode, 1 = power down) */\n+\twritel(0, pmatop + PMA_CML_GL_PM_CFG0);\n+\n+\t/* This value switches clock from C0_REFCK to CLK_REF_I */\n+\tval = u32_encode_bits(WRITE_MASK_VALUE, COMM_CFG_WRITE_MASK_MASK);\n+\tval |= COMM_CFG_ENABLE;\n+\tval |= u32_encode_bits(WRITE_DATA_VALUE, COMM_CFG_WRITE_DATA_MASK);\n+\n+\tfor (i = 0; i < PMA_REG_COUNT; i++) {\n+\t\tu32 offset = i * PMA_HWT_REFCK_STRIDE;\n+\n+\t\t/* Disable C0_REFCK and 100 ohm termination */\n+\t\twritel(0, pmatop + PMA_HWT_REFCK_R_EN + offset);\n+\t\twritel(0, pmatop + PMA_HWT_REFCK_TERM_EN + offset);\n+\n+\t\t/* Switch clock from C0_REFCK to CLK_REF_I */\n+\t\toffset = i * PMA_COMM_CFG_0_1_STRIDE;\n+\t\twritel(val, pmatop + PMA_COMM_CFG_0_1 + offset);\n+\t}\n+\n+\ttc956x_reset_deassert(chip, id, MAC_RESET_PMA);\n+\n+\tWARN_ON(readl_poll_timeout(emac_ctl, val, val & EMAC_INIT_DONE, 50, 1000000));\n+}\n+\n+static int tc956x_mac_speed_select(struct tc956x_data *td, int speed)\n+{\n+\tphy_interface_t phy_interface = td->plat->phy_interface;\n+\tstruct net_device *netdev;\n+\tint i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(mac_speed); i++) {\n+\t\tif (mac_speed[i].speed != speed)\n+\t\t\tcontinue;\n+\n+\t\tif (mac_speed[i].phy_interface == phy_interface)\n+\t\t\treturn mac_speed[i].sp_sel;\n+\t}\n+\tnetdev = dev_get_drvdata(td->dev);\n+\tnetdev_err(netdev, \"%s/%d unsupported\\n\",\n+\t\t phy_modes(phy_interface), speed);\n+\n+\treturn -EOPNOTSUPP;\n+}\n+\n+static int tc956x_mac_configure(struct tc956x_data *td, int speed)\n+{\n+\tvoid __iomem *emac_ctl = td->auxbus_data->emac_ctl;\n+\tint sp_sel;\n+\tu32 val;\n+\n+\tsp_sel = tc956x_mac_speed_select(td, speed);\n+\tif (sp_sel < 0)\n+\t\treturn sp_sel;\n+\n+\tval = readl(emac_ctl);\n+\tval |= EMAC_LPIHWCLKEN;\n+\tval &= ~EMAC_INV_SGM_SIG_DET;\n+\tval = u32_replace_bits(val, PCS_CLK_PHY, EMAC_PHY_INF_SEL_MASK);\n+\tval = u32_replace_bits(val, sp_sel, EMAC_SP_SEL_MASK);\n+\twritel(val, emac_ctl);\n+\n+\treturn 0;\n+}\n+\n+static int tc956x_mac_enable(struct tc956x_data *td)\n+{\n+\tconst struct tc956x_chip *chip = td->auxbus_data->chip;\n+\tstruct plat_stmmacenet_data *plat = td->plat;\n+\tu32 id = td->auxbus_data->mac_id;\n+\tint ret;\n+\n+\ttc956x_clock_enable(chip, id, MAC_CLOCK_TX);\n+\ttc956x_clock_enable(chip, id, MAC_CLOCK_RX);\n+\ttc956x_clock_enable(chip, id, MAC_CLOCK_ALL);\n+\tif (id)\n+\t\ttc956x_clock_enable(chip, id, MAC_CLOCK_RMII);\n+\n+\t/* Set the speed related registers */\n+\tret = tc956x_mac_configure(td, plat->max_speed);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\ttc956x_reset_deassert(chip, id, MAC_RESET_MAC);\n+\ttc956x_pma_init(td);\n+\ttc956x_reset_deassert(chip, id, MAC_RESET_XPCS);\n+\n+\treturn 0;\n+}\n+\n+static void tc956x_mac_disable(struct tc956x_data *td)\n+{\n+\tconst struct tc956x_chip *chip = td->auxbus_data->chip;\n+\tu32 id = td->auxbus_data->mac_id;\n+\n+\ttc956x_reset_assert(chip, id, MAC_RESET_MAC);\n+\ttc956x_reset_assert(chip, id, MAC_RESET_PMA);\n+\ttc956x_reset_assert(chip, id, MAC_RESET_XPCS);\n+\n+\ttc956x_clock_disable(chip, id, MAC_CLOCK_ALL);\n+\ttc956x_clock_disable(chip, id, MAC_CLOCK_RX);\n+\ttc956x_clock_disable(chip, id, MAC_CLOCK_TX);\n+\tif (id)\n+\t\ttc956x_clock_disable(chip, id, MAC_CLOCK_RMII);\n+}\n+\n+static void tc956x_mac_init_state(struct tc956x_data *td)\n+{\n+\tconst struct tc956x_chip *chip = td->auxbus_data->chip;\n+\tu32 id = td->auxbus_data->mac_id;\n+\n+\ttc956x_clock_disable(chip, id, MAC_CLOCK_125M);\n+\ttc956x_clock_disable(chip, id, MAC_CLOCK_312_5M);\n+\n+\ttc956x_mac_disable(td);\n+}\n+\n+/*\n+ * Override method for dwxgmac301_dma_ops->init_rx_chan\n+ *\n+ * This differs from the dwxgmac301_dma_ops->init_rx_chan by translating the DMA\n+ * address for TC956x internal bus. The window that provides DMA access to PCI\n+ * is linearly mapped at 0x10_0000_0000.\n+ */\n+static void tc956x_dma_init_rx_chan(struct stmmac_priv *priv,\n+\t\t\t\t void __iomem *ioaddr,\n+\t\t\t\t struct stmmac_dma_cfg *dma_cfg,\n+\t\t\t\t dma_addr_t phy, u32 chan)\n+{\n+\tdma_addr_t translated = phy + TC956X_SLV00_SRC_ADDR;\n+\n+\tdwxgmac2_dma_init_rx_chan(priv, ioaddr, dma_cfg, phy, chan);\n+\n+\twritel(upper_32_bits(translated),\n+\t ioaddr + XGMAC_DMA_CH_RxDESC_HADDR(chan));\n+\twritel(lower_32_bits(translated),\n+\t ioaddr + XGMAC_DMA_CH_RxDESC_LADDR(chan));\n+}\n+\n+/* Override method for dwxgmac301_dma_ops->init_tx_chan */\n+static void tc956x_dma_init_tx_chan(struct stmmac_priv *priv,\n+\t\t\t\t void __iomem *ioaddr,\n+\t\t\t\t struct stmmac_dma_cfg *dma_cfg,\n+\t\t\t\t dma_addr_t phy, u32 chan)\n+{\n+\tdma_addr_t translated = phy + TC956X_SLV00_SRC_ADDR;\n+\n+\tdwxgmac2_dma_init_tx_chan(priv, ioaddr, dma_cfg, phy, chan);\n+\n+\twritel(upper_32_bits(translated),\n+\t ioaddr + XGMAC_DMA_CH_TxDESC_HADDR(chan));\n+\twritel(lower_32_bits(translated),\n+\t ioaddr + XGMAC_DMA_CH_TxDESC_LADDR(chan));\n+}\n+\n+/* Override method for dwxgmac210_desc_ops->set_addr */\n+static void tc956x_desc_set_addr(struct dma_desc *p, dma_addr_t addr)\n+{\n+\tdma_addr_t translated = addr + TC956X_SLV00_SRC_ADDR;\n+\n+\tp->des0 = cpu_to_le32(lower_32_bits(translated));\n+\tp->des1 = cpu_to_le32(upper_32_bits(translated));\n+}\n+\n+/* Override method for dwxgmac210_desc_ops->set_sec_addr */\n+static void tc956x_desc_set_sec_addr(struct dma_desc *p, dma_addr_t addr,\n+\t\t\t\t bool is_valid)\n+{\n+\tdma_addr_t translated = addr + TC956X_SLV00_SRC_ADDR;\n+\n+\tp->des2 = cpu_to_le32(lower_32_bits(translated));\n+\tp->des3 = cpu_to_le32(upper_32_bits(translated));\n+}\n+\n+/*\n+ * Use mac_setup to apply the override methods above.\n+ *\n+ * The memory for the modified ops structures is pre-allocated as part of\n+ * struct tc956x_data.\n+ */\n+static int tc956x_mac_setup(void *apriv, struct mac_device_info *mac)\n+{\n+\tstruct stmmac_priv *priv = apriv;\n+\tstruct stmmac_desc_ops *desc;\n+\tstruct stmmac_dma_ops *dma;\n+\tstruct tc956x_data *td;\n+\n+\ttd = priv->plat->bsp_priv;\n+\n+\t/* dwxgmac301_dma_ops needs extending to provide DMA address translation */\n+\tdma = &td->dma;\n+\t*dma = dwxgmac301_dma_ops;\n+\tdma->init_rx_chan = tc956x_dma_init_rx_chan;\n+\tdma->init_tx_chan = tc956x_dma_init_tx_chan;\n+\tmac->dma = dma;\n+\n+\t/* dwxgmac210_desc_ops also needs extending for the same reason */\n+\tdesc = &td->desc;\n+\t*desc = dwxgmac210_desc_ops;\n+\tdesc->set_addr = tc956x_desc_set_addr;\n+\tdesc->set_sec_addr = tc956x_desc_set_sec_addr;\n+\tmac->desc = desc;\n+\n+\tpriv->hw = mac;\n+\n+\treturn dwxgmac2_setup(priv);\n+}\n+\n+static int tc956x_pcs_init(struct stmmac_priv *priv)\n+{\n+\tstruct xpcs_regmap_config xpcs_regmap_cfg;\n+\tvoid __iomem *emac = priv->ioaddr;\n+\tstruct regmap *xpcs_regmap;\n+\tvoid __iomem *xpcs_addr;\n+\tstruct dw_xpcs *xpcs;\n+\n+\txpcs_addr = emac + DWMAC_XPCS_OFFSET;\n+\txpcs_regmap = devm_regmap_init_mmio(priv->device, xpcs_addr,\n+\t\t\t\t\t &xpcs_regmap_config);\n+\tif (IS_ERR(xpcs_regmap))\n+\t\treturn PTR_ERR(xpcs_regmap);\n+\n+\txpcs_regmap_cfg.regmap = xpcs_regmap;\n+\txpcs_regmap_cfg.reg_indir = true;\n+\n+\txpcs = devm_xpcs_regmap_register(priv->device, &xpcs_regmap_cfg);\n+\tif (IS_ERR(xpcs))\n+\t\treturn PTR_ERR(xpcs);\n+\n+\txpcs_config_eee_mult_fact(xpcs, priv->plat->mult_fact_100ns);\n+\tpriv->hw->phylink_pcs = xpcs_to_phylink_pcs(xpcs);\n+\n+\treturn 0;\n+}\n+\n+static struct phylink_pcs *tc956x_select_pcs(struct stmmac_priv *priv,\n+\t\t\t\t\t phy_interface_t interface)\n+{\n+\treturn priv->hw->phylink_pcs;\n+}\n+\n+static void tc956x_fix_mac_speed(void *bsp_priv, phy_interface_t interface,\n+\t\t\t\t int speed, unsigned int mode)\n+{\n+\tstruct tc956x_data *td = bsp_priv;\n+\n+\ttc956x_mac_configure(td, speed);\n+\ttc956x_pma_init(td);\n+}\n+\n+static int tc956x_dwmac_suspend(struct device *dev, void *bsp_priv)\n+{\n+\tstruct tc956x_data *td = bsp_priv;\n+\n+\ttc956x_mac_disable(td);\n+\n+\treturn 0;\n+}\n+\n+static int tc956x_dwmac_resume(struct device *dev, void *bsp_priv)\n+{\n+\tstruct tc956x_data *td = bsp_priv;\n+\n+\treturn tc956x_mac_enable(td);\n+}\n+\n+/* Called by tc956x_dwmac_probe(); return errors with dev_err_probe() */\n+static int tc956x_dwmac_parse_dt(struct tc956x_data *td)\n+{\n+\tstruct device_node *mdio_node;\n+\tstruct device *dev = td->dev;\n+\tstruct device_node *np;\n+\n+\tnp = dev_of_node(dev);\n+\tif (!np)\n+\t\treturn dev_err_probe(dev, -EINVAL, \"no devicetree node\\n\");\n+\n+\t/* Find the MDIO bus */\n+\tfor_each_child_of_node(np, mdio_node) {\n+\t\tif (of_device_is_compatible(mdio_node,\n+\t\t\t\t\t \"snps,dwmac-mdio\"))\n+\t\t\tbreak;\n+\t}\n+\n+\t/* Pass the MDIO bus (if there is one) to the core driver */\n+\tif (mdio_node) {\n+\t\ttd->plat->mdio_node = mdio_node;\n+\t\ttd->plat->mdio_bus_data->needs_reset = true;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int tc956x_lookup_max_speed(phy_interface_t phy_interface)\n+{\n+\tswitch (phy_interface) {\n+\tcase PHY_INTERFACE_MODE_SGMII:\n+\tcase PHY_INTERFACE_MODE_2500BASEX:\n+\t\treturn SPEED_2500;\n+\n+\tdefault:\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+}\n+\n+/* Called by tc956x_dwmac_probe(); return errors with dev_err_probe() */\n+static int tc956x_plat_dat_init(struct tc956x_data *td)\n+{\n+\tstruct plat_stmmacenet_data *plat;\n+\tphy_interface_t phy_interface;\n+\tstruct device *dev = td->dev;\n+\tstruct stmmac_axi *axi;\n+\tu32 speed;\n+\tint ret;\n+\tu32 i;\n+\n+\tphy_interface = device_get_phy_mode(dev);\n+\tif (phy_interface < 0)\n+\t\treturn -ENODEV;\n+\n+\t/* The platform structure is allocated with devm_kzalloc() */\n+\tplat = stmmac_plat_dat_alloc(dev);\n+\tif (!plat)\n+\t\treturn -ENOMEM;\n+\n+\tret = tc956x_lookup_max_speed(phy_interface);\n+\tif (ret < 0)\n+\t\treturn dev_err_probe(dev, ret, \"unsupported phy speed\\n\");\n+\tspeed = ret;\n+\n+\tplat->core_type = DWMAC_CORE_XGMAC;\n+\tplat->bus_id = td->auxbus_data->mac_id;\n+\tplat->phy_interface = phy_interface;\n+\tplat->mdio_bus_data = &td->mdio_bus_data;\n+\t/* Parent PCI device is used for DMA */\n+\tplat->dma_device = dev->parent;\n+\tplat->dma_cfg = &td->dma_cfg;\n+\tplat->dma_cfg->pbl = 32;\n+\tplat->dma_cfg->pblx8 = true;\n+\n+\t/*\n+\t * Our MAC clock rate is fixed at 125 MHz. For XGMAC, clk_csr 0\n+\t * represents \"divide by 62\" and gets the best rate under 2.5 MHz.\n+\t */\n+\tplat->clk_csr = 0;\t/* MDC clock = clk_csr_i / 62 */\n+\tplat->force_sf_dma_mode = 1;\n+\tplat->max_speed = speed;\n+\tplat->unicast_filter_entries = 32;\n+\n+\t/*\n+\t * TC956x has 8 RX queues but we observe significantly reduced RX\n+\t * bandwidth if we don't have at least 8k FIFO space per queue, so\n+\t * by default we avoid using all the queues.\n+\t */\n+\tplat->rx_queues_to_use = 4;\n+\n+\t/*\n+\t * TX956x has 8 TX queues but only #0 to #3 work for general IP traffic.\n+\t * For now we will limit the driver to only these queues.\n+\t */\n+\tplat->tx_queues_to_use = 4;\n+\n+\t/*\n+\t * Oversized FIFOs result in reduced performance in bandwidth tests.\n+\t * Limit them to 8KiB per queue, or the total available.\n+\t */\n+\tplat->tx_fifo_size =\n+\t\tmin(TC956X_TX_FIFO_KB, 8 * plat->tx_queues_to_use) * SZ_1K;\n+\tplat->rx_fifo_size =\n+\t\tmin(TC956X_RX_FIFO_KB, 8 * plat->rx_queues_to_use) * SZ_1K;\n+\tplat->host_dma_width = 36;\n+\n+\tplat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;\n+\tplat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR;\n+\n+\t/* Default RX chan is set to queue index (0..rx_queues_to_use-1) */\n+\tfor (i = 0; i < plat->rx_queues_to_use; i++)\n+\t\tplat->rx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;\n+\n+\tfor (i = 0; i < plat->tx_queues_to_use; i++) {\n+\t\tplat->tx_queues_cfg[i].weight = 12;\n+\t\tplat->tx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;\n+\n+\t\t/* Only queues 5-8 support time-based scheduling on TC956X */\n+\t\tif (i >= 5)\n+\t\t\tplat->tx_queues_cfg[i].tbs_en = 1;\n+\t}\n+\n+\tplat->fix_mac_speed = tc956x_fix_mac_speed;\n+\tplat->suspend = tc956x_dwmac_suspend;\n+\tplat->resume = tc956x_dwmac_resume;\n+\tplat->mac_setup = tc956x_mac_setup;\n+\tplat->pcs_init = tc956x_pcs_init;\n+\tplat->select_pcs = tc956x_select_pcs;\n+\n+\tplat->bsp_priv = td;\n+\tplat->clk_ptp_rate = TC956X_PTP_CLOCK_RATE;\n+\n+\t/* AXI Configuration */\n+\taxi = &td->axi;\n+\taxi->axi_lpi_en = 1;\n+\taxi->axi_wr_osr_lmt = 31;\n+\taxi->axi_rd_osr_lmt = 31;\n+\t/* All sizes (2^2..2^8) are supported */\n+\taxi->axi_blen_regval = DMA_AXI_BLEN_MASK;\n+\tplat->axi = axi;\n+\n+\tplat->mac_port_sel_speed = speed;\n+\tplat->flags = STMMAC_FLAG_MULTI_MSI_EN | STMMAC_FLAG_TSO_EN;\n+\n+\ttd->plat = plat;\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * The domain was created with IRQ_DOMAIN_FLAG_DESTROY_GC, so any mapped IRQs\n+ * will be disposed when the domain is removed (when the device is destroyed).\n+ */\n+static int tc956x_stmmac_resources_init(struct tc956x_data *td,\n+\t\t\t\t\tstruct stmmac_resources *res)\n+{\n+\tstruct irq_domain *irq_domain = td->irq_domain;\n+\tu32 i;\n+\n+\tres->irq = irq_create_mapping(irq_domain, HWIRQ_EVENT);\n+\tif (!res->irq)\n+\t\treturn -EINVAL;\n+\n+\tfor (i = 0; i < td->plat->tx_queues_to_use; i++) {\n+\t\tres->tx_irq[i] = irq_create_mapping(irq_domain, HWIRQ_TX0 + i);\n+\t\tif (!res->tx_irq[i])\n+\t\t\treturn -EINVAL;\n+\t}\n+\n+\tfor (i = 0; i < td->plat->rx_queues_to_use; i++) {\n+\t\tres->rx_irq[i] = irq_create_mapping(irq_domain, HWIRQ_RX0 + i);\n+\t\tif (!res->tx_irq[i])\n+\t\t\treturn -EINVAL;\n+\t}\n+\n+\tres->addr = td->auxbus_data->emac;\n+\n+\treturn 0;\n+}\n+\n+static int tc956x_dwmac_probe(struct auxiliary_device *adev,\n+\t\t\t const struct auxiliary_device_id *id)\n+{\n+\tstruct stmmac_resources res = { };\n+\tstruct device *dev = &adev->dev;\n+\tstruct tc956x_data *td;\n+\tint ret;\n+\n+\ttd = devm_kzalloc(dev, sizeof(*td), GFP_KERNEL);\n+\tif (!td)\n+\t\treturn -ENOMEM;\n+\n+\ttd->dev = dev;\n+\ttd->auxbus_data = dev_get_platdata(dev);\n+\tif (!td->auxbus_data)\n+\t\treturn dev_err_probe(dev, -EINVAL, \"no platform data\\n\");\n+\n+\tret = tc956x_plat_dat_init(td);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = tc956x_dwmac_parse_dt(td);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\ttd->irq_domain = tc956x_msigen_irq_domain_instantiate(td);\n+\tif (IS_ERR(td->irq_domain))\n+\t\treturn dev_err_probe(dev, PTR_ERR(td->irq_domain),\n+\t\t\t\t \"failed to instantiate IRQ domain\\n\");\n+\n+\t/* Put the MAC in a known initial state */\n+\ttc956x_mac_init_state(td);\n+\n+\tret = tc956x_stmmac_resources_init(td, &res);\n+\tif (ret)\n+\t\treturn dev_err_probe(dev, ret,\n+\t\t\t\t \"failed to initialize stmmac resources\\n\");\n+\n+\tret = tc956x_mac_enable(td);\n+\tif (ret)\n+\t\treturn dev_err_probe(dev, ret, \"failed to enable MAC\\n\");\n+\n+\tret = stmmac_dvr_probe(dev, td->plat, &res);\n+\tif (ret)\n+\t\treturn dev_err_probe(dev, ret, \"failed stmmac probe\\n\");\n+\n+\treturn 0;\n+}\n+\n+static void tc956x_dwmac_remove(struct auxiliary_device *adev)\n+{\n+\tstruct device *dev = &adev->dev;\n+\tstruct net_device *ndev = dev_get_drvdata(dev);\n+\tstruct stmmac_priv *priv = netdev_priv(ndev);\n+\tstruct tc956x_data *td = priv->plat->bsp_priv;\n+\n+\tstmmac_dvr_remove(dev);\n+\ttc956x_mac_disable(td);\n+}\n+\n+static const struct auxiliary_device_id tc956x_dwmac_ids[] = {\n+\t{ .name = TC956X_PCIE_DRIVER_NAME \".\" TC956X_XGMAC_DEV_NAME, },\n+\t{ },\n+};\n+MODULE_DEVICE_TABLE(auxiliary, tc956x_dwmac_ids);\n+\n+static struct auxiliary_driver tc956x_dwmac_driver = {\n+\t.name\t\t= DRIVER_NAME,\n+\t.probe\t\t= tc956x_dwmac_probe,\n+\t.remove\t\t= tc956x_dwmac_remove,\n+\t.id_table\t= tc956x_dwmac_ids,\n+\t.driver = {\n+\t\t.name\t= DRIVER_NAME,\n+\t\t.pm\t= &stmmac_simple_pm_ops,\n+\t\t.owner\t= THIS_MODULE,\n+\t},\n+};\n+module_auxiliary_driver(tc956x_dwmac_driver);\n+\n+MODULE_DESCRIPTION(\"Toshiba TC956x PCIe Ethernet Network Driver\");\n+MODULE_LICENSE(\"GPL\");\ndiff --git a/include/soc/toshiba/tc956x-dwmac.h b/include/soc/toshiba/tc956x-dwmac.h\nnew file mode 100644\nindex 0000000000000..5ca39cf764be9\n--- /dev/null\n+++ b/include/soc/toshiba/tc956x-dwmac.h\n@@ -0,0 +1,84 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+\n+/*\n+ * Copyright (C) 2026 by RISCstar Solutions Corporation. All rights reserved.\n+ */\n+\n+#ifndef __TOSHIBA_TC956X_DWMAC_H__\n+#define __TOSHIBA_TC956X_DWMAC_H__\n+\n+#include <linux/compiler_types.h>\n+#include <linux/types.h>\n+\n+#define TC956X_PCIE_DRIVER_NAME\t\"tc956x_pci\"\n+\n+#define TC956X_XGMAC_DEV_NAME\t\"dwmac-tc956x\"\n+\n+/* Starting address of the space translated by the PCIe endpoint bridge */\n+#define TC956X_SLV00_SRC_ADDR\t0x0000001000000000ULL\n+\n+enum tc956x_reset_id {\n+\tMAC_RESET_MAC\t\t= 7,\n+\tMAC_RESET_PMA\t\t= 30,\n+\tMAC_RESET_XPCS\t\t= 31,\n+};\n+\n+enum tc956x_clock_id {\n+\tMAC_CLOCK_TX\t\t= 7,\n+\tMAC_CLOCK_RX\t\t= 14,\n+\tMAC_CLOCK_ALL\t\t= 31,\n+\tMAC_CLOCK_125M\t\t= 29,\n+\tMAC_CLOCK_312_5M\t= 30,\n+\tMAC_CLOCK_RMII\t\t= 15,\t/* eMAC 1 only */\n+};\n+\n+/**\n+ * struct tc956x_dwmac_data - Structure passed to stmmac auxiliary devices.\n+ * @chip:\t\tContext pointer needed for reset and clock operations\n+ * @emac:\t\tI/O mapped address used by eMAC\n+ * @emac_ctl:\t\tI/O mapped address used for eMAC control\n+ * @msigen:\t\tI/O mapped address used by MSIGEN\n+ * @msigen_irq:\t\tIRQ number used by MSIGEN\n+ * @rev_id:\t\tChip revision ID (for quirks)\n+ * @mac_id:\t\tUnique device ID (0 or 1)\n+ *\n+ * This structure is passed via platform data to the stmmac auxiliary devices.\n+ */\n+struct tc956x_dwmac_data {\n+\tconst struct tc956x_chip *chip;\n+\tvoid __iomem *emac;\n+\tvoid __iomem *emac_ctl;\n+\tvoid __iomem *msigen;\n+\tunsigned int msigen_irq;\n+\tu8 rev_id;\n+\tu8 mac_id;\n+};\n+\n+extern void tc956x_reset_clock_set(const struct tc956x_chip *chip, bool reset,\n+\t\t\t\t bool reg0, bool set, u8 bit);\n+\n+static inline void tc956x_reset_assert(const struct tc956x_chip *chip,\n+\t\t\t\t u8 mac_id, enum tc956x_reset_id id)\n+{\n+\ttc956x_reset_clock_set(chip, true, !mac_id, true, (u8)id);\n+}\n+\n+static inline void tc956x_reset_deassert(const struct tc956x_chip *chip,\n+\t\t\t\t\t u8 mac_id, enum tc956x_reset_id id)\n+{\n+\ttc956x_reset_clock_set(chip, true, !mac_id, false, (u8)id);\n+}\n+\n+static inline void tc956x_clock_enable(const struct tc956x_chip *chip,\n+\t\t\t\t u8 mac_id, enum tc956x_clock_id id)\n+{\n+\ttc956x_reset_clock_set(chip, false, !mac_id, true, (u8)id);\n+}\n+\n+static inline void tc956x_clock_disable(const struct tc956x_chip *chip,\n+\t\t\t\t\tu8 mac_id, enum tc956x_clock_id id)\n+{\n+\ttc956x_reset_clock_set(chip, false, !mac_id, false, (u8)id);\n+}\n+\n+#endif /* __TOSHIBA_TC956X_DWMAC_H__*/\n", "prefixes": [ "net-next", "10/12" ] }